如何在PL/pgSQL中正确使用`RETURN NEXT`?

tin*_*lyx 2 postgresql plpgsql

我正在尝试使用返回表的PL/pgSQL(PostgreSQL 9.3)函数编写循环.我RETURN NEXT;在循环中的每个查询后都没有使用参数,下面的示例如plpgsql错误"RETURN NEXT在表返回函数中没有函数和OUT参数",以及其他地方.但是,我仍然收到一条错误消息:

ERROR:  query has no destination for result data
HINT:  If you want to discard the results of a SELECT, use PERFORM instead.
Run Code Online (Sandbox Code Playgroud)

下面是重现问题的最小代码示例.任何人都可以请帮助解释如何修复测试代码以返回表格?

提前致谢.

最小的例子:

CREATE OR REPLACE FUNCTION test0()
 RETURNS TABLE(y integer, result text) AS $func$
DECLARE
    yr RECORD;
BEGIN
    FOR yr IN SELECT * FROM generate_series(1,10,1) AS y_(y) 
    LOOP
        RAISE NOTICE 'Computing %', yr.y;
        SELECT yr.y, 'hi';
        RETURN NEXT;
    END LOOP;
    RETURN;
END
$func$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

Cra*_*ger 7

给出的示例可以完全替换为RETURN QUERY:

BEGIN
    RETURN QUERY SELECT y_.y, 'hi' FROM generate_series(1,10,1) AS y_(y)
END;
Run Code Online (Sandbox Code Playgroud)

这将是一个很大更快.

通常,您应该尽可能避免迭代,而是支持面向集合的操作.

return next循环中不可避免的情况(这是非常罕见的,并且大多数情况下仅限于需要异常处理时),您必须设置OUT参数值或表参数,然后return next不带参数.

在这种情况下,你的问题是SELECT yr.y, 'hi';没有做任何事情的线.您假设a的隐式目标SELECT是out参数,但事实并非如此.您必须使用out参数作为循环变量,如@peterm,使用赋值或使用SELECT INTO:

FOR yr IN SELECT * FROM generate_series(1,10,1) AS y_(y) 
LOOP
    RAISE NOTICE 'Computing %', yr.y;
    y := yr.y;
    result := 'hi';
    RETURN NEXT;
END LOOP;
RETURN;
Run Code Online (Sandbox Code Playgroud)


Erw*_*ter 6

@Craig已经解释过了

另外,如果你真的需要一个循环,你可以让这个更简单/更便宜。您不需要声明额外的记录变量并重复分配。plpgsql 中的赋值相对昂贵。直接赋值给OUT声明的变量RETURNS TABLE。这些在代码中随处可见,FOR循环也可以分配给变量列表。手册:

目标是记录变量、行变量或逗号分隔的标量变量列表。

创建或替换函数 test0()
  返回表(y 整数,结果文本)
  语言 plpgsql AS
$函数$
宣布
    年记录;  -- 现在不需要了
开始
   FOR y,结果 IN
      选择 g, 'text_'::text || G
      来自generate_series(1,10) g
   环形
      发出通知“计算%”,y;
      返回下一个;
   结束循环;
结尾
$函数$;

额外积分

  • 不要使用标识符y两次(作为OUT参数和列别名),而您可以轻松避免它。那是一把上了膛的步枪。如果无法避免这种情况,请对列进行表限定。

  • 没有参数的决赛RETURN是很好的形式,但完全是可选的。当控制到达final时END,自动返回完整的结果。

  • gin自动FROM generate_series(1,10) g表别名列别名,除非给出显式列别名。它实际上与 相同FROM generate_series(1,10) g(g)


pet*_*erm 5

一种方法可以做到这一点

CREATE OR REPLACE FUNCTION test0()
 RETURNS TABLE(y integer, result text) AS $$
BEGIN
    FOR y, result IN 
        SELECT s.y, 'hi' result FROM generate_series(1,10,1) AS s(y)
    LOOP
        RETURN NEXT;
    END LOOP;
END
$$ LANGUAGE plpgsql;

SELECT * FROM test0();
Run Code Online (Sandbox Code Playgroud)

结果:

| 是 | 结果 |
|----|--------|
| 1 | 你好|
| 2 | 你好|
| 3 | 你好|
| 4 | 你好|
| 5 | 你好|
| 6 | 你好|
| 7 | 你好|
| 8 | 你好|
| 9 | 你好|
| 10 | 10 你好|

这是一个SQLFiddle演示

  • 很有用,但如果您能解释“为什么”它有效,那就太好了,因为原始海报显然对输出变量有点困惑。 (2认同)