SQL SAP HANA 中基于过程的更新语句
SQL Update Statement based on Procedure in SAP HANA
我正在创建更新语句,根据 table 的名称
为 table 列生成 SHA256
第一步:我创建了一个获取 table 列的过程,将它们全部连接在一列中,然后格式化为所需的格式。
-- 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
我找到了适合我需要的解决方案,但也许还有其他更简单或更适合table的方法:
我将更新语句添加到我的过程中,并将所有生成的查询插入到临时 table 列中,然后使用 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;
欢迎任何其他解决方案或改进
谢谢
@SonOfHarpy 的解决方案在技术上可行,但有几个问题,即:
- 不必要地使用临时 tables
- 过于复杂的字符串赋值方法
- 使用固定系统 table 架构 (
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 的所有废话,再次使代码更容易理解并且不易出现问题。
输入参数名称现在可以正确反映其含义并反映 TABLE_NAME
(NVARCHAR(256)
) 的 HANA 字典数据类型。
该过程现在由两个命令(SELECT
和 EXECUTE IMMEDIATE
)组成,每个命令执行该过程的基本任务:
- 构建有效的 SQL 更新命令字符串。
- 正在执行 SQL 命令。
我删除了无用的行注释,但在代码中留下了调试语句作为注释,这样就可以在不执行命令的情况下查看 SQL 字符串。
显然,要使其正常工作,需要注释掉 EXECUTE...
行并且必须取消注释调试行。
比解决方案的构建更令人担忧的是它的目的。
看起来 SHA
列应该用作一种 shorthand 行数据指纹。 UPDATE
方法当然是事后处理 activity 但将 "finger-printing" 留给执行更新的时间。
另外,table 设计的一个重要部分(SHA
列应该包含指纹)远离 table 定义。
替代方法可以是生成的列:
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
*/
有了这个,"generator" 方法可以用于 table definition/modification 时间,但所有实际数据处理将由 HANA 自动完成,只要值在table.
此外,由于指纹始终是最新的,因此无需单独调用该过程。
我正在创建更新语句,根据 table 的名称
为 table 列生成 SHA256第一步:我创建了一个获取 table 列的过程,将它们全部连接在一列中,然后格式化为所需的格式。
-- 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
我找到了适合我需要的解决方案,但也许还有其他更简单或更适合table的方法:
我将更新语句添加到我的过程中,并将所有生成的查询插入到临时 table 列中,然后使用 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;
欢迎任何其他解决方案或改进 谢谢
@SonOfHarpy 的解决方案在技术上可行,但有几个问题,即:
- 不必要地使用临时 tables
- 过于复杂的字符串赋值方法
- 使用固定系统 table 架构 (
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 的所有废话,再次使代码更容易理解并且不易出现问题。
输入参数名称现在可以正确反映其含义并反映 TABLE_NAME
(NVARCHAR(256)
) 的 HANA 字典数据类型。
该过程现在由两个命令(SELECT
和 EXECUTE IMMEDIATE
)组成,每个命令执行该过程的基本任务:
- 构建有效的 SQL 更新命令字符串。
- 正在执行 SQL 命令。
我删除了无用的行注释,但在代码中留下了调试语句作为注释,这样就可以在不执行命令的情况下查看 SQL 字符串。
显然,要使其正常工作,需要注释掉 EXECUTE...
行并且必须取消注释调试行。
比解决方案的构建更令人担忧的是它的目的。
看起来 SHA
列应该用作一种 shorthand 行数据指纹。 UPDATE
方法当然是事后处理 activity 但将 "finger-printing" 留给执行更新的时间。
另外,table 设计的一个重要部分(SHA
列应该包含指纹)远离 table 定义。
替代方法可以是生成的列:
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
*/
有了这个,"generator" 方法可以用于 table definition/modification 时间,但所有实际数据处理将由 HANA 自动完成,只要值在table.
此外,由于指纹始终是最新的,因此无需单独调用该过程。