18

我在 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 在这里抱怨,因为我的代码看起来很像文档中的示例,除了我的函数返回 TABLE 而不是 SETOF。没有 OUT 参数。

我最终设法让它使用

RETURN QUERY SELECT result_row.column1, result_row.column2, ...;

但是必须一直列出所有列是丑陋且难以维护的。我相信一定有更好的方法。

4

1 回答 1

27

RETURN NEXT只返回当前持有的输出参数。手册

如果你用输出参数声明了函数,那么只写RETURN NEXT不带表达式。

你反对:

没有OUT参数。

输出参数在函数参数中使用关键字OUTor声明INOUT或者RETURNS在您的子句中隐式声明:

RETURNS TABLE(column1 integer, column2 boolean, ...)

这里column1column2也是OUT参数。

这应该这样做:

CREATE OR REPLACE FUNCTION my_function()
  RETURNS TABLE(column1 integer, column2 boolean, ...)
  LANGUAGE plpgsql STABLE AS
$func$
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
$func$;

注册类型更简单

您可以使用已注册的复合类型进一步简化:

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在某些情况下使用,您可以随时添加一个参数(使用默认值)来打开/关闭它。

于 2012-12-26T11:19:54.123 回答