业务场景需求:
在HANA里如何实现动态的SQL控制,比如需要多个单据里,实现某个自定义字段不允许重复
一般的写法是需要在每个业务单据里加对应的存储过程控制,这样的话,需要在每个业务单据里进行控制,SQL维护量比较大,尝试想看看有没有一段统一的批量动态SQL,可以实现自动根据object_type 来实现动态查询对应的SAP表。
比如:
IF :object_type = '13' AND :transaction_type = N'A' THEN
SELECT COUNT(*) INTO SAP_COUNT FROM
(
SELECT COUNT(A."U_ID") FROM
(
SELECT DISTINCT T1."DocEntry",T1."U_ID"
FROM OINV T0
INNER JOIN INV1 T1 ON T0."DocEntry" = T1."DocEntry"
WHERE
T0."CANCELED" = 'N'
AND IFNULL(T1."U_ID",'') IN (SELECT "U_ID" FROM INV1 WHERE "DocEntry" = list_of_cols_val_tab_del)
) A
GROUP BY A."U_ID"
HAVING COUNT(*) > 1
)
;
IF SAP_COUNT > 0
THEN
error := 1;
error_message := '此ID已存在,不允许重复传入SAP,请核实!';
END IF;
END IF;
实现方案:
尝试在存储过程里定义变量,然后通过变量承接构建的SQL查询,最后使用EXECUTE IMMEDIATE执行构建好的SQL。此方法可以省去每当需要控制一个单据的时候,就重新写一段重复值,控制的SQL,只需要把对应的object_type 和表名加进去即可,如果不需要进行控制了,也可以直接取消对应的object_type 和表名。
SQL如下:
ALTER PROCEDURE SBO_SP_TransactionNotification
(
in object_type nvarchar(30), -- SBO Object Type
in transaction_type nchar(1), -- [A]dd, [U]pdate, [D]elete, [C]ancel, C[L]ose
in num_of_cols_in_key int,
in list_of_key_cols_tab_del nvarchar(255),
in list_of_cols_val_tab_del nvarchar(255)
)
LANGUAGE SQLSCRIPT
AS
-- Return values
error int; -- Result (0 for no error)
error_message nvarchar (200); -- Error string to be displayed
SAP_COUNT int; --定义SAP计数变量
v_sql NVARCHAR(1000); --定义构建SQL变量
table1 NVARCHAR(50); --定义表1变量
table2 NVARCHAR(50); --定义表2变量
begin
error := 0;
error_message := N'Ok';
-----------------------------------------------------------------------------------------
IF (
object_type = '15' OR --销售交货
object_type = '16' OR --销售退货
object_type = '13' OR --应收发票
object_type = '14' OR --应收贷项凭证
object_type = '20' OR --采购收货
object_type = '21' OR --采购退货
object_type = '18' OR --应付发票
object_type = '19' OR --应付贷项凭证
object_type = '59' OR --收货
object_type = '60' OR --发货
object_type = '67' OR --库存转储
object_type = '10000071' OR --库存盘点过账
object_type = '202' --生产订单
)
AND transaction_type IN ('A')
THEN
--确定主表,然后插入到table1里
SELECT
CASE :object_type
WHEN 15 THEN 'ODLN' --销售交货
WHEN 16 THEN 'ORDN' --销售退货
WHEN 13 THEN 'OINV' --应收发票
WHEN 14 THEN 'ORIN' --应收贷项凭证
WHEN 20 THEN 'OPDN' --采购收货
WHEN 21 THEN 'ORPD' --采购退货
WHEN 18 THEN 'OPCH' --应付发票
WHEN 19 THEN 'ORPC' --应付贷项凭证
WHEN 59 THEN 'OIGN' --收货
WHEN 60 THEN 'OIGE' --发货
WHEN 67 THEN 'OWTR' --库存转储
WHEN 10000071 THEN 'OIQR' --库存盘点过账
WHEN 202 THEN 'OWOR' --生产订单
END
INTO table1
FROM DUMMY;
--确定子表,然后插入到table2里
SELECT
CASE :object_type
WHEN 15 THEN 'DLN1' --销售交货
WHEN 16 THEN 'RDN1' --销售退货
WHEN 13 THEN 'INV1' --应收发票
WHEN 14 THEN 'RIN1' --应收贷项凭证
WHEN 20 THEN 'PDN1' --采购收货
WHEN 21 THEN 'RPD1' --采购退货
WHEN 18 THEN 'PCH1' --应付发票
WHEN 19 THEN 'RPC1' --应付贷项凭证
WHEN 59 THEN 'IGN1' --收货
WHEN 60 THEN 'IGE1' --发货
WHEN 67 THEN 'OWTR' --库存转储
WHEN 10000071 THEN 'IQR1' --库存盘点过账
WHEN 202 THEN 'WOR1' --生产订单
END
INTO table2
FROM DUMMY;
-- 构建动态 SQL
v_sql :=
'SELECT COUNT(*) FROM
(
SELECT COUNT(A."U_ID") FROM
(
SELECT DISTINCT T1."DocEntry",T1."U_ID"
FROM "' || :table1 || '" T0
INNER JOIN "' || :table2 || '" T1 ON T0."DocEntry" = T1."DocEntry"
WHERE T0."CANCELED" = ''N''
AND IFNULL(T1."U_ID",'''') IN (SELECT "U_ID" FROM "' || :table2 || '" WHERE "DocEntry" = ' || :list_of_cols_val_tab_del || ')) A GROUP BY A."U_ID" HAVING COUNT(*) > 1);'
;
-- 执行并传递绑定变量
EXECUTE IMMEDIATE :v_sql INTO SAP_COUNT;
IF IFNULL(SAP_COUNT,0) > 0
THEN
error := 1;
error_message := N'【'|| :table1 ||'】,此ID已存在,不允许重复传入SAP,请核实!';
END IF;
END IF;
-----------------------------------------------------------------------------------------
-- Select the return values
select :error, :error_message FROM dummy;
end;
注意事项:
- v_sql里面的拼接字符串,一定要注意区分单引号,因为在拼接的时候,用到单引号的地方,需要用两个单引号进行表示。
- 此方案一定要核实所有的业务单据,因为很容易发生各种各样的SQL报错,尤其是单引号、分号的问题,双引号后面不要跟回车。
- 此方案仅提供思路,具体需要根据实际情况进行更改SQL代码控制。
- 自行搜索一下EXECUTE IMMEDIATE的语法。