我在PostgreSQL 9.2中有一个plpgsql函数,它返回一个表。该函数运行几个SELECT,返回与函数相同的列,然后返回这些结果或引发异常,具体取决于某些检查。我可以看到这样做的唯一方法是使用FOR ... LOOP,但我无法找到一种方便的方法来返回行。
我想做这样的事情:
CREATE OR REPLACE FUNCTION my_function()
RETURNS TABLE(column1 integer, column2 boolean, ...)
AS $BODY$
DECLARE
result_row RECORD;
BEGIN
FOR result_row IN (SELECT * FROM other_function_returning_same_columns()) LOOP
IF something_wrong_with(result_row) THEN
RAISE EXCEPTION 'Something went wrong';
END IF;
RETURN NEXT result_row;
END LOOP;
END
$BODY$ LANGUAGE plpgsql STABLE;
这给了我一个错误:
错误:RETURN NEXT在OUT参数的功能中无法使用参数
我不确定为什么Postgres在这里抱怨,因为我的代码看起来很像documentation中的示例,除了我的函数返回TABLE而不是SETOF。没有OUT参数。
我最终设法使用
让它工作RETURN QUERY SELECT result_row.column1, result_row.column2, ...;
但是必须一直列出所有列是丑陋的,难以维护。我相信一定有更好的方法。
答案 0 :(得分:21)
RETURN NEXT
只返回RETURNS
子句(column1, column2, ..)
中声明的参数。您无法为此表单提供参数。
没有OUT参数。
RETURNS TABLE(column1 integer, column2 boolean, ...)
中声明的参数与OUT
参数实际上相同。
这应该这样做:
CREATE OR REPLACE FUNCTION my_function()
RETURNS TABLE(column1 integer, column2 boolean, ...) AS
$BODY$
BEGIN
FOR column1, column2, ... IN
SELECT * FROM other_function_returning_same_columns()
LOOP
IF something_wrong_with(column1, column2, ...) THEN
RAISE EXCEPTION 'Something went wrong';
END IF;
RETURN NEXT;
END LOOP;
END
$BODY$ LANGUAGE plpgsql STABLE;
您可以使用已注册的复合类型进一步简化:
CREATE TYPE mytype (column1 integer, column2 boolean, ...);
或者,如果您的类型恰好与表定义匹配,那么您已经拥有该类型,因为每个表名都可以用作PostgreSQL中的类型名。然后简化:
CREATE OR REPLACE FUNCTION my_function()
RETURNS SETOF mytype LANGUAGE plpgsql STABLE AS
$func$
DECLARE
_r mytype;
BEGIN
FOR _r IN
SELECT * FROM other_function_returning_same_columns()
LOOP
IF something_wrong_with(_r) THEN
RAISE EXCEPTION 'Something went wrong';
END IF;
RETURN NEXT _r;
END LOOP;
END
$func$;
我很确定所有这些都可以更有效地组织更多。
如果您将RAISE
命令集成到辅助函数something_wrong_with()
中并更方便地命名它(或者它是邪恶的双胞胎)everything_groovy()
,那么您可以完全替换my_function()
这个简单的查询:
SELECT *
FROM other_function_returning_same_columns() f
WHERE everything_groovy(f);
或者将RAISE
集成到基函数other_function_returning_same_columns()
中以进一步简化(并使其更快)。如果您在某些情况下只想RAISE EXCEPTION
,则可以随时添加一个参数(默认值)来打开/关闭它。