【问题标题】:plpgsql error "RETURN NEXT cannot have a parameter in function with OUT parameters" in table-returning function表返回函数中的plpgsql错误“RETURN NEXT不能在具有OUT参数的函数中具有参数”
【发布时间】:2012-12-11 23:03:00
【问题描述】:

我在 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, ...;

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

【问题讨论】:

  • 您是否需要抛出异常,还是只想返回符合条件的行?
  • 是的,我确实希望在某些情况下抛出异常。

标签: postgresql exception-handling plpgsql


【解决方案1】:

RETURN NEXT 只返回当前持有的输出参数。 The manual:

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

你反对:

没有OUT 参数。

输出参数在函数参数中声明,关键字OUTINOUT隐含在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,您可以随时添加一个参数(带有默认值)来打开/关闭它。

【讨论】:

  • 谢谢。看起来我无论做什么都必须列出所有列,但这比我以前的代码少。
  • @EM:嗯,总是有更多选择。我为我的答案添加了替代方案。
  • 再次感谢!将检查放入另一个函数是一个有趣的想法。在这种情况下它并没有真正的帮助,因为实际代码比我的示例更复杂,但可能还有其他函数可以使用这个技巧而不是循环遍历结果。 (它可以在这里工作,但比列出列更复杂。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-11-06
  • 2018-01-25
  • 1970-01-01
  • 2014-01-12
  • 1970-01-01
  • 2021-10-13
  • 1970-01-01
相关资源
最近更新 更多