Pus*_*Pal 7 postgresql dynamic-sql parameter plpgsql postgresql-9.5
我在 PostgreSQL 9.5 中编写了一个 PL/pgSQL 函数。它编译得很好,但是当我从 pgAdmin3 调用它时,它给了我一个错误。似乎用函数中传递的参数替换列的动态查询不起作用。
下面是我的功能:
CREATE OR REPLACE FUNCTION insertRecordsForNotification(username text, state text, district text, organizationId text, bloodGroup text, status text, approveRejectStatus text, emailSubject text, emailBody text, notificationStatus text) RETURNS boolean AS $$
DECLARE
id int;
r moyadev.user%rowtype;
_where text :=
concat_ws(' AND '
, CASE WHEN state IS NOT NULL THEN 'state = $2' END
, CASE WHEN district IS NOT NULL THEN 'district = $3' END
, CASE WHEN bloodGroup IS NOT NULL THEN 'bloodGroup = $5' END
, CASE WHEN status IS NOT NULL THEN 'status = $6' END
, CASE WHEN approveRejectStatus IS NOT NULL THEN 'approve_reject_status = $7' END);
_sql text := 'INSERT INTO moyadev.notification_email_details (id, youth_enrollment_id, youth_email, email_subject, email_body, status, attempt, sent_date, last_updated_by, last_updated) SELECT uuid_generate_v4(), id, email, $8, $9, $10, null, null,$1, now() FROM moyadev.youth_enrollment';
BEGIN
SELECT * into r FROM moyadev.user u where u.user_key=$1;
if (r.level='DISTRICT') then
_where := _where || ' AND ' || 'district=r.district' || ' AND ' || 'state=r.state' || ' AND ' || 'fk_id=r.fk_id';
elseif (r.level='STATE') then
_where := _where || ' AND ' || 'state=r.state' || ' AND ' || 'fk_id=r.fk_id';
elseif (r.level='NATIONAL') then
_where := _where || ' AND ' || 'fk_id=r.fk_id';
elseif (r.level='UNIT') then
_ where := _where || ' AND ' || 'district=r.district' || ' AND ' || 'state=r.state' || ' AND ' || 'fk_id=r.fk_id';
end if;
IF _where <> '' THEN
_sql := _sql || ' WHERE ' || _where;
EXECUTE format(_sql);
END IF;
raise notice 'sql: %', _sql;
RETURN 'TRUE';
END;
$$ LANGUAGE PLPGSQL;
Run Code Online (Sandbox Code Playgroud)
它编译得很好,但是当我使用以下命令调用它时会出现以下错误:
select insertRecordsForNotification('nssnationalappr@mailinator.com',null,null,null,null,'ACTIVE','APPROVED','test email','test email','PENDING');
Run Code Online (Sandbox Code Playgroud)
Run Code Online (Sandbox Code Playgroud)ERROR: there is no parameter $8 SQL state: 42P02 Context: PL/pgSQL function insertrecordsfornotification(text,text,text,text,text,text,text,text,text,text) line 39 at EXECUTE
如何正确使用参数值?
Erw*_*ter 15
你混淆了几件事。要将值传递给EXECUTE,请使用USING子句。你不需要format()这里。
CREATE OR REPLACE FUNCTION insert_records_for_notification(
_username text
, _state text
, _district text
, _bloodgroup text
, _status text
, _approverejectstatus text
, _emailsubject text
, _emailbody text
, _notificationstatus text)
RETURNS boolean AS
$func$
DECLARE
r moyadev.user%rowtype;
_where text;
_sql text :=
'INSERT INTO moyadev.notification_email_details (id, youth_enrollment_id, youth_email, email_subject, email_body, status, attempt,sent_date, last_updated_by, last_updated)
SELECT uuid_generate_v4(), id, email, $7, $8, $9, null, null,$1, now()
FROM moyadev.youth_enrollment';
BEGIN
SELECT * INTO r FROM moyadev.user u WHERE u.user_key = _username;
_where := concat_ws(' AND '
, CASE WHEN state IS NOT NULL THEN 'state = $2' END
, CASE WHEN district IS NOT NULL THEN 'district = $3' END
, CASE WHEN bloodGroup IS NOT NULL THEN 'bloodgroup = $4' END
, CASE WHEN status IS NOT NULL THEN 'status = $5' END
, CASE WHEN approveRejectStatus IS NOT NULL THEN 'approve_reject_status = $6' END
, CASE r.level
WHEN 'DISTRICT' THEN 'district = $10 AND state = $11 AND fk_id = $12'
WHEN 'UNIT' THEN 'district = $10 AND state = $11 AND fk_id = $12'
WHEN 'STATE' THEN 'state = $11 AND fk_id = $12'
WHEN 'NATIONAL' THEN 'fk_id = $12'
END);
IF _where <> '' THEN
_sql := _sql || ' WHERE ' || _where;
EXECUTE _sql
USING $1, $2, $3, $4, $5, $6, $7, $8, $9, r.district, r.state, r.fk_id;
END IF;
RAISE NOTICE 'sql: %', _sql;
RETURN true; -- boolean!
END
$func$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)
难道不是串连参数值到SQL字符串。非常乏味、缓慢、容易出错并且容易受到 SQL 注入的影响。而是将值传递给EXECUTEwithUSING子句。有关的:
我删除了未使用的变量和未使用的参数id int;。相应地调整了序数参考 ( organizationId text$n)。
不要混淆函数体中的$n符号EXECUTE(参考USING子句中的项目)和$n函数体中的符号(参考函数参数)!有关的:
简化连接WHERE子句的逻辑。存在极端情况错误:如果初始分配导致空字符串,您将以AND- 语法错误开始。
采用避免命名冲突的命名约定。参数名称在函数中的所有语句中都是可见的(但不在内部EXECUTE!)。不要使用与列名冲突的变量名。一个常见的约定是在参数和变量名称前加上_.
我的建议是避免在 Postgres 中使用大小写混合的标识符,尤其是在使用动态 SQL 时。
SO的相关答案:
| 归档时间: |
|
| 查看次数: |
28270 次 |
| 最近记录: |