Слон, корова и козел. Расширение стандартного функционала SAP HANA недокументированными функциями

3667
3

Введение.

Однажды, читая SCN я наткнулся на интересную статью по решению математической задачки с помощью SAP HANA. Оригинальная статья –

http://scn.sap.com/community/developer-center/hana/blog/2013/03/05/using-sap-hana-to-count-my-elephants-cows-and-goats

Я же хочу немного прокомментировать предложенные решения и слегка их дополнить.

Постановка задачи.

У Вас есть 100$, потратив их полностью (1), вы хотите купить ровно 100 игрушек (2).

Есть всего три варианта покупки: Слон за 10$, Корова за 3$, и Козел за 0.5$ (3).

Сколько необходимо купить слонов, коров и козлов, чтобы они удовлетворяли всем (трём) условиям.

Предложенное решение.

Первый и, пожалуй, самый очевидный способ поиска решения, который пришёл в голову коллегам – это сделать три вложенных цикла и если все условия выполнены – добавить сообщение в таблицу из которой потом выбирается результат.

CREATE TABLE PRACTICE_TEST.MY_LOG

(LOG_ENTRY varchar(100));

--procedure to make entries in log tables

CREATE PROCEDURE PRACTICE_TEST.PROC_MY_LOG

(IN v_in_msg VARCHAR (100) )

LANGUAGE SQLSCRIPT

AS

BEGIN

INSERT INTO PRACTICE_TEST.MY_LOG ( LOG_ENTRY) VALUES (:v_in_msg);

END;

--dropping any other procedure with similar name (just in case)

DROP PROCEDURE PRACTICE_TEST.PROC_PUZZLE_OUTPUT;

--Creating the actual stored procedure to process the business logic

CREATE PROCEDURE PRACTICE_TEST.PROC_PUZZLE_OUTPUT

LANGUAGE SQLSCRIPT

AS

ELEPHANT_COUNT integer;

COW_COUNT integer;

GOAT_COUNT integer;

ELEPHANT integer;

CNTR integer;

v_msg varchar(100);

Begin

ELEPHANT_COUNT := 1;

CNTR := 0;

v_msg := '';

While ELEPHANT_COUNT < 10

DO

COW_COUNT := 1;

While COW_COUNT < 100

DO

GOAT_COUNT := 1;

while GOAT_COUNT < 100

Do

CNTR := CNTR + 1;

if MOD(:cntr, 1000) = 0 then

v_msg := 'CNTR RUN COUNT = '||:CNTR;

call PRACTICE_TEST.PROC_MY_LOG(:v_msg);

end if;

if ((:ELEPHANT_COUNT + :COW_COUNT + :GOAT_COUNT) = 100) AND ((:ELEPHANT_COUNT * 10) + (:COW_COUNT * 3) + (:GOAT_COUNT * 0.5) = 100)

THEN

v_msg := 'CNTR RUN COUNT = '||:CNTR || 'Goat Loop : Elephant count = '||:ELEPHANT_COUNT||' Cow count = '||:COW_COUNT||'Goat count = '||:GOAT_COUNT;

call PRACTICE_TEST.PROC_MY_LOG(:v_msg);

end if;

GOAT_COUNT := :GOAT_COUNT + 1;

END While;

COW_COUNT := :COW_COUNT + 1;

End While;

ELEPHANT_COUNT := :ELEPHANT_COUNT + 1;

end while;

End;

--deleting the log entries for previous runs

truncate table PRACTICE_TEST.MY_LOG;

--running the procedure having business logic

call PRACTICE_TEST.PROC_PUZZLE_OUTPUT;

--Checking the results in the log

SELECT * from PRACTICE_TEST.MY_LтоOG ASC;

Задача вроде решена, и даже с использованием HANA, но не использована вся её мощь. Да и решение получилось свойственное скорее языкам подобным C++или JAVA. Просто переложили логику на SQL-script. Примем время работы этого варианта- (1) за точку отсчёта. 

Второй вариант - более интересный.

Формируется «вспомогательная» таблица со значениями от 1 до 100, а далее при запросе три раза JOIN к себе же, ну а в WHERE – условия, которые необходимы для решения задачи:

DROP TABLE COACH.HELPER;

DROP PROCEDURE COACH.INIT_GAME;

CREATE COLUMN TABLE "COACH"."HELPER" ("ID" INTEGER CS_INT NOT NULL);

CREATE PROCEDURE COACH.INIT_GAME() LANGUAGE SQLSCRIPT AS

v_count INT;

BEGIN

       FOR v_count IN 0 .. 100 DO

             INSERT INTO COACH.HELPER VALUES(:v_count);

       END FOR;

END;

CALL COACH.INIT_GAME();

SELECT

 e.id elephants, c.id cows, g.id goats FROM COACH.HELPER

Ограниченный доступ

Для прочтения полной версии статьи необходимо зайти как зарегистрированный пользователь.

Комментарии:

Олег Башкатов (Рейтинг: 7711) 16:20, 09 сентября 2013

Вы заметили, что автор статьи, на которую Вы ссылаетесь, решил задачу, вообще говоря, неверно :-) (нашел только 1 решение, а их два)?
 
Предварительное упрощение условий должно быть, в любом случае (хоть это и SAP HANA).
ведь вся задача - это решение системы
C = (20 - 19*E/5);
G = 100 - E - C;
C,G,E - целые неотрицательные числа.
 
решение которой сводится к перебору значений E кратным 5, то есть всего два значения: 0 и 5.
то есть в итоге ответа два:
E=0;С=20;G=80
E=5;С=1;G=94
12:03, 10 сентября 2013

Надежда Быкова (Рейтинг: 137)

Автор статьи использовал в алгоритме решения одно необъявленное условие - в наборе игрушек должна быть хотя бы одна игрушка каждого вида. Кстати, в одном из своих комментариев он сделал замечание по поводу двойного решения системы.
14:23, 10 сентября 2013

Олег Башкатов (Рейтинг: 7711)

Тогда получается и того легче - даже перебора не нужно.
Ответ получается однозначно.
 
Суть моего комментария: нельзя брать и "вслепую перебирать решения", какие бы вычислительные мощности не были.

Любое воспроизведение запрещено.
Копирайт © «Издательство ООО «Эксперт РП»