Sql 在执行时传递ROWTYPE参数
我正在Postgres中开发一个函数,其目的是为查询的每个记录恢复包含在一组函数中的检查结果的值。这些函数中只有一个返回正确的值。这些函数有一个comun前缀“fn\u condico\u”,并将“my\u table”类型的对象作为参数接收 由于进行检查的函数数量未知,我决定参考Postgres目录,从表Sql 在执行时传递ROWTYPE参数,sql,postgresql,plpgsql,postgresql-8.3,Sql,Postgresql,Plpgsql,Postgresql 8.3,我正在Postgres中开发一个函数,其目的是为查询的每个记录恢复包含在一组函数中的检查结果的值。这些函数中只有一个返回正确的值。这些函数有一个comun前缀“fn\u condico\u”,并将“my\u table”类型的对象作为参数接收 由于进行检查的函数数量未知,我决定参考Postgres目录,从表pg_catalog.pg_proc中搜索前缀为'fn_condico_'的函数,并使用execute动态执行它们 我的问题是如何为传递正确的形状参数 如何在上述函数中的注释的EXECUTE命
pg_catalog.pg_proc
中搜索前缀为'fn_condico_'的函数,并使用execute动态执行它们
我的问题是如何为传递正确的形状参数
如何在上述函数中的注释的EXECUTE
命令中正确传递v_记录
execute 'select ' || v_function.proname || '(' || v_record || ')'; -- ???
函数示例:
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;
我相信您的问题在于函数中的
execute
命令试图插值v_record
的值,这实际上将其转换为离散的参数列表,而不是函数所期望的本机行类型
如果您愿意更改每个函数的参数类型,那么这可能是处理此问题的最简单方法。如果不是,则需要某种方法将本机行类型传递给动态函数调用。尽管这看起来很糟糕,但我认为类似的方法会奏效:
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 '
do $ZOOM$
declare
v_rec my_table%rowtype;
begin
select *
into v_rec
from my_table
where id = ' || v_record.id || ';
perform ' || func_name || '(v_rec);
end;
$ZOOM$
';
end loop;
end loop;
end;
$$
此外,我认为您需要将
选择
更改为执行
(如上所述)。。。要么这样做,要么做一个选择进入
这个问题在中得到了回答。因此,我想与大家分享这项决议
数据库管理员回答 在Postgres 8.4或更高版本中,您可以使用
EXECUTE
的USING
子句安全有效地传递值。这在您的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';
电话:
- 如果使用
set search_path='pg_catalog'在函数体中,则
模式中的表不再可见。全局设置搜索路径将是一个非常糟糕的主意。效果在设置期间保持不变。您可以使用public
将其包含到事务中,但这仍然是一个坏主意。相反,如果确实需要,请仅设置函数的环境,如演示的那样。SET LOCAL
有关Postgres中搜索路径的详细信息: - 仅仅执行一个
,而不分配或返回结果是没有意义的。使用SELECT
的EXECUTE
子句,然后INTO
。在现代Postgres中,您可以用returnnext
返回查询执行
替换内部循环
- 在构建动态查询字符串时,使用
和quote_ident()
正确转义标识符和文字。在现代Postgres中,您将使用quote_literal()
format()
- 将整行强制转换为它的字符串表示、转义和强制转换不是很有效。此替代方法必须重复从表中读取数据,但在其他情况下更干净(行直接作为值传递):
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;
看起来您正试图用过程替换关系。您试图解决的真正问题是什么?我需要以友好的方式运行一组函数。这个过程是一个更大的过程的一部分,更复杂,不能用关系范式进行。这些函数可以随着时间的推移而增长,这就是为什么我尝试动态执行它们,以便添加新函数不会影响这个更大的过程@如果我错了,Clodoaldonet会纠正我,但我猜“do”命令在Postgres 8.3中不起作用@Hambone@GeisonSantos你可能是对的。不幸的是,我进入博士后的洗礼是9.2分。如果有人不在9.5上,我会郑重建议他们放弃一切并升级。单是改进后的排序就值得入场费。
SELECT * FROM test_conditions();
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;
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;