【问题标题】:SQL Update Statement based on Procedure in SAP HANA基于 SAP HANA 中过程的 SQL 更新语句
【发布时间】:2018-12-29 11:24:35
【问题描述】:

我正在创建一个更新语句,它根据表的名称为表列生成 SHA256

第一步:我创建了一个获取表格列的过程,将它们全部连接到一个列中,然后格式化为所需的格式。

-- 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

【问题讨论】:

    标签: sql hash sap hana sha


    【解决方案1】:

    @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 函数更改为更短的||(双管道)运算符,代码变得更易于阅读,因为以前的嵌套函数调用现在是简单的链式连接。

    通过使用SELECT ... INTO variable,可以避免临时表的所有废话,再次使代码更易于理解且不易出现问题。

    输入参数名称现在可以正确反映其含义并反映 TABLE_NAME (NVARCHAR(256)) 的 HANA 字典数据类型。

    该过程现在包含两个命令(SELECTEXECUTE IMMEDIATE),每个命令都执行该过程的一项基本任务:

    1. 构建有效的 SQL 更新命令字符串。
    2. 正在执行 SQL 命令。

    我删除了无用的line-cmets,但在代码中留下了一个调试语句作为注释,这样就可以在不执行命令的情况下查看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 自动完成。
    此外,由于指纹始终是最新的,因此无需单独调用该过程。

    【讨论】:

      【解决方案2】:

      我找到了适合我需要的解决方案,但也许还有其他更简单或更合适的方法:

      我将更新语句添加到我的过程中,并将所有生成的查询插入到一个临时表列中,并使用 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;
      

      欢迎任何其他解决方案或改进 谢谢

      【讨论】:

        猜你喜欢
        • 2018-05-31
        • 1970-01-01
        • 2022-06-11
        • 2013-02-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多