Gei*_*tos 5 postgresql dynamic-sql plpgsql postgresql-8.3
我正在 Postgres 中开发一个函数,旨在为查询的每个记录恢复一组函数中包含的检查结果的值。只有这些函数之一会返回正确的值。这些函数有一个公共前缀“fn_condition_”,并接收一个“my_table”类型的对象作为参数。
由于进行检查的函数数量未知,我决定查阅 Postgres 目录,从表中pg_catalog.pg_proc
搜索带有前缀“fn_condition_”的函数并使用EXECUTE
.
我的问题是将参数传递给EXECUTE
.
create or replace function test_conditions()
returns void as
$$
declare
v_record my_table%rowtype;
v_function pg_proc%rowtype;
begin
set search_path = 'pg_catalog';
for v_record in (select * from my_table where id in (1,2,3)) loop
for v_function in (
SELECT p.proname
FROM pg_namespace n
JOIN pg_proc p
ON p.pronamespace = n.oid
WHERE n.nspname = 'operacional'
and p.proname like ('fn_condition\\_%')
order by p.proname)
loop
-- execute 'select ' || v_function.proname || '(' || v_record || ')'; -- ???
end loop;
end loop;
end;
$$
language plpgsql;
Run Code Online (Sandbox Code Playgroud)
如何在上面的函数中v_record
正确传递注释EXECUTE
命令?
execute 'select ' || v_function.proname || '(' || v_record || ')'; -- ???
Run Code Online (Sandbox Code Playgroud)
示例函数:
create or replace function fn_condition_1(p_record my_table)
returns bigint as
$$
begin
if ($1.atributo1 > $1.atributo2) then
return 1;
end if;
return null;
end;
$$
language plpgsql;
Run Code Online (Sandbox Code Playgroud)
在 Postgres 8.4 或更高版本中,您将使用USING
of 子句EXECUTE
安全有效地传递值。这在您的 8.3 版中尚不可用。在您的版本中,它可以像这样工作:
CREATE OR REPLACE FUNCTION test_conditions()
RETURNS SETOF bigint AS
$func$
DECLARE
_rec record;
_func text;
_result bigint;
BEGIN
FOR _func in
SELECT p.proname
FROM pg_catalog.pg_namespace n
JOIN pg_catalog.pg_proc p ON p.pronamespace = n.oid
WHERE n.nspname = 'operacional'
AND p.proname LIKE E'fn\\_condition\\_%' -- no parens, proper string
ORDER BY p.proname -- no parens
LOOP
FOR _rec in
SELECT * FROM my_table WHERE id IN (1,2,3) -- no parens needed
LOOP
EXECUTE 'SELECT ' || quote_ident(_func) || '(' || quote_literal(_rec) || ')'
INTO _result;
RETURN NEXT _result;
END LOOP;
END LOOP;
END
$func$ LANGUAGE plpgsql SET search_path = 'public';
Run Code Online (Sandbox Code Playgroud)
称呼:
SELECT * FROM test_conditions();
Run Code Online (Sandbox Code Playgroud)
如果您set search_path = 'pg_catalog';
在函数体中使用,那么public
架构中的表将不再可见。全局SET
搜索路径将是一个非常糟糕的主意。效果在设置期间保持不变。您可以使用SET LOCAL
将其包含在事务中,但这仍然是一个坏主意。相反,如果你真的需要,只设置函数的环境,就像演示的那样。
有关 Postgres 中搜索路径的更多信息:
仅执行 aSELECT
而不分配或返回结果将毫无意义。使用and then的INTO
子句。在现代 Postgres 中,您可以用.EXECUTE
RETURN NEXT
RETURN QUERY EXECUTE
在构建动态查询字符串时,使用quote_ident()
和quote_literal()
正确转义标识符和文字。在现代 Postgres 中,您将使用format()
.
将整行转换为它的字符串表示形式,转义并返回,效率不是很高。这种替代方法必须重复从表中读取,否则会更清晰(该行直接作为值传递):
FOR i IN
VALUES (1), (2), (3)
LOOP
EXECUTE 'SELECT ' || quote_ident(_func) || '(t) FROM my_table t WHERE id = ' || i
INTO _result;
RETURN NEXT _result;
END LOOP;
Run Code Online (Sandbox Code Playgroud)您还可以使用此 SQL 函数从根本上简化示例函数:
CREATE OR REPLACE FUNCTION fn_condition_1(p_record my_table)
RETURNS bigint AS
$func$
SELECT CASE WHEN $1.atributo1 > $1.atributo2 THEN bigint '1' END
$func$ LANGUAGE sql;
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
2491 次 |
最近记录: |