Оператор обновления SQL на основе процедуры в SAP HANA - PullRequest
0 голосов
/ 29 декабря 2018

Я создаю оператор обновления, который генерирует SHA256 для столбцов таблицы на основе имени таблицы

1-й шаг: я создал процедуру, которая получает столбцы таблицы, объединяет все в один столбец, затем форматирует вжелаемый формат.

-- Procedure code : Extract table's columns list, conctenate it and format it

Create procedure SHA_PREP (in inp1 nvarchar(20))
as 
begin

SELECT concat(concat('hash_sha256(',STRING_AGG(A, ', ')),')')  AS Names
FROM (
    SELECT  concat('to_varbinary(IFNULL("',concat(COLUMN_NAME,'",''0''))')) as A
    FROM    SYS.TABLE_COLUMNS
    WHERE SCHEMA_NAME = 'SCHEMA_NAME' AND TABLE_NAME = :inp1
    AND COLUMN_NAME not in ('SHA')
    ORDER BY POSITION 
    );
end;

/* Result of this procedures : 
hash_sha256(
to_varbinary("ID"),to_varbinary(IFNULL("COL1",'0')),to_varbinary(IFNULL("COL2",'0')) )
*/

-- Update Statement needed 

UPDATE "SCHEMA_NAME"."TABLE_NAME"
SET "SHA" = CALL "SCHEMA_NAME"."SHA_PREP"('SCHEMA_NAME')
WHERE "ID" = 99 -- a random filter

Ответы [ 2 ]

0 голосов
/ 07 января 2019

Техническое решение @SonOfHarpy работает, но имеет несколько проблем, а именно:

  • ненужное использование временных таблиц
  • чрезмерно сложный подход к присвоению строк
  • использованиеисправлена ​​схема системной таблицы (SYS.TABLE_COLUMNS) вместо синонима PUBLIC
  • неверный тип данных и имя переменной для входного параметра

Улучшенная версия кода выглядит следующим образом:

create procedure SHA_PREP (in TABLE_NAME nvarchar(256))
as 
begin
declare SQL_STR nvarchar(5000);

    SELECT 
          'UPDATE "SCHEMA_NAME"."TABLE_NAME" SET "SHA"= hash_sha256(' || STRING_AGG(A, ', ') || ')'
          into SQL_STR
    FROM (
        SELECT  
            'TO_VARBINARY(IFNULL("'|| "COLUMN_NAME" ||'",''0''))' as A
        FROM TABLE_COLUMNS
        WHERE 
                "SCHEMA_NAME" = 'SCHEMA_NAME' 
           AND "TABLE_NAME" = :TABLE_NAME
           AND "COLUMN_NAME" != 'SHA'
        ORDER BY POSITION 
        );

  --  select :sql_str from dummy; -- this is for debugging output only
    EXECUTE IMMEDIATE (:SQL_STR);
end; 

Путем изменения функций CONCAT на более короткий оператор || (double-pipe) код становится намного проще для чтения, поскольку ранее вложенные вызовы функций теперь являются простыми сцепленными цепочками.

С помощью SELECT ... INTO variable можно избежать всей бессмыслицы с временной таблицей, что снова делает код более простым для понимания и менее подверженным проблемам.

Имя входного параметра теперь правильно отражает егоозначает и отражает тип данных словаря HANA для TABLE_NAME (NVARCHAR(256)).

Процедура теперь состоит из двух команд (SELECT и EXECUTE IMMEDIATE), каждая из которых выполняет существенную задачу процедуры:

  1. Создание допустимой строки команды обновления SQL.
  2. Выполнение команды SQL.

Я удалил бесполезные строковые комментарии, но оставил оператор отладки в качестве комментария в коде, чтобы можно было просмотреть строку SQL без необходимостивыполнить команду.Очевидно, что для того, чтобы это работало, строку EXECUTE... необходимо закомментировать, а строку отладки - не закомментировать.

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

Кроме того, он занимает существенную часть дизайна таблицы (чтостолбец SHA должен содержать отпечаток пальца) вне определения таблицы.

Альтернативой этому может быть ОБЩАЯ КОЛОННА:

create  table test (aaa int, bbb int);
alter table test add (sha varbinary (256) generated always as 
                        hash_sha256(to_varbinary(IFNULL("AAA",'0'))
                                 ,  to_varbinary(IFNULL("BBB",'0'))
                                    )
                       );

insert into test (aaa, bbb) values (12, 32);

select * from test;

/*
AAA BBB SHA                                                             
12  32  B6602F58690CA41488E97CD28153671356747C951C55541B6C8D8B8493EB7143
*/ 

При этом подход "генератора" можетбудет использоваться для определения / изменения таблицы, но вся фактическая обработка данных будет автоматически выполняться HANA при каждом изменении значений в таблице.
Кроме того, не требуется никаких отдельных вызовов процедуры, так как отпечатки пальцев всегда будутбудь в курсе.

0 голосов
/ 29 декабря 2018

Я нашел решение, которое удовлетворяет моим потребностям, но, возможно, есть и другие более простые или более подходящие подходы:

Я добавил оператор обновления в свою процедуру и вставил весь сгенерированный запрос во столбец временной таблицы,извините, используя EXECUTE IMMEDIATE

Create procedure SHA_PREP (in inp1 nvarchar(20))
as 
begin
/* ********************************************************** */
DECLARE SQL_STR VARCHAR(5000);

-- Create a temporary table to store a query in
create local temporary table #temp1 (QUERY varchar(5000));
-- Insert the desirable query into the QUERY column (Temp Table)
insert into #temp1(QUERY)
SELECT concat('UPDATE "SCHEMA_NAME"."TABLE_NAME" SET "SHA" =' ,concat(concat('hash_sha256(',STRING_AGG(A, ', ')),')'))
FROM (
    SELECT  concat('to_varbinary(IFNULL("',concat(COLUMN_NAME,'",''0''))')) as A
    FROM    SYS.TABLE_COLUMNS
    WHERE SCHEMA_NAME = 'SCHEMA_NAME' AND TABLE_NAME = :inp1
    AND COLUMN_NAME not in ('SHA')
    ORDER BY POSITION 
    );
end;
/* QUERY : UPDATE "SCHEMA_NAME"."TABLE_NAME" SET "SHA" = 
hash_sha256(to_varbinary("ID"),to_varbinary(IFNULL("COL1",'0')),to_varbinary(IFNULL("COL2",'0'))) */
SELECT QUERY into SQL_STR FROM "SCHEMA_NAME".#temp1;

--Excuting the query 
EXECUTE IMMEDIATE (:SQL_STR);

-- Dropping the temporary table 
DROP TABLE "SCHEMA_NAME".#temp1;

/* ********************************************************** */
end;

Любые другие решения или улучшения приветствуются. Спасибо

...