我想创建一个删除行并在没有错误的情况下返回 true 的函数:
CREATE OR REPLACE FUNCTION s_grnplm_tt.sp_del_stts_cd(num text, package_name text, stts_cd text)
returns bool
LANGUAGE plpgsql as
$func$
BEGIN
EXECUTE
'delete FROM s_grnplm_'||num||'tt.log_copy d WHERE d.package_name =' ||package_name|| ' and d.stts_cd = $1'
using stts_cd;
return true;
end;
$func$;
我正在调用一个函数: select s_grnplm_tt.sp_del_stts_cd('089', '0202_20232211_2434', 'U')
但我收到错误: SQL 错误 [42601]:错误:“_20232211_2434”处或附近的语法错误其中:PL/pgSQL 函数 sp_del_stts_cd(text,text,text) 第 3 行在 EXECUTE 语句
首先,你应该阅读一些有关 SQL 注入问题的内容。
其次,当你对动态SQL(
EXECUTE
)语句有问题时,那么你应该使用RAISE NOTICE
语句并显示执行的SQL语句。那么问题就干净了:
delete FROM s_grnplm_089tt.log_copy d WHERE d.package_name =0202_20232211_2434 and d.stts_cd = $1
谓词中缺少撇号
d.package_name =0202_20232211_2434
。
您的函数可以重写为:
CREATE OR REPLACE FUNCTION s_grnplm_tt.sp_del_stts_cd(num text,
package_name text,
stts_cd text)
RETURNS void
LANGUAGE plpgsql as
$func$
DECLARE sqlstr text;
BEGIN
sqlstr := format('DELETE FROM %I d WHERE d.package_name = %L AND d.stts_cd = $1',
's_grnplm_' || num || 'tt.log_copy', package_name);
RAISE NOTICE '%', sqlstr;
EXECUTE sqlstr USING stts_cd;
END;
$func$;
现在,查询是正确的:
DELETE FROM "s_grnplm_089tt.log_copy" d WHERE d.package_name = '0202_20232211_2434' AND d.stts_cd = $1
动态 SQL 只需要将 SQL 标识符作为字符串传递。其他可以通过使用
USING
子句传递二进制。因此谓词 d.package_name =
的使用方式应与 d.stts_cd =
谓词类似:
BEGIN
sqlstr := format('DELETE FROM %I d WHERE d.package_name = $1 AND d.stts_cd = $2',
's_grnplm_' || num || 'tt.log_copy');
RAISE NOTICE '%', sqlstr;
EXECUTE sqlstr USING package_name, stts_cd;
END;