【问题标题】:How to use `RETURN NEXT`in PL/pgSQL correctly?如何在 PL/pgSQL 中正确使用 `RETURN NEXT`?
【发布时间】:2014-12-28 01:11:35
【问题描述】:

我正在尝试使用返回表的 PL/pgSQL (PostgreSQL 9.3) 函数编写一个循环。我在循环中的每个查询之后使用了不带参数的RETURN NEXT;,遵循plpgsql error "RETURN NEXT cannot have a parameter in function with OUT parameters" in table-returning function 和其他地方的示例。但是,我仍然收到一条错误消息:

ERROR:  query has no destination for result data
HINT:  If you want to discard the results of a SELECT, use PERFORM instead.

重现问题的最小代码示例如下。谁能帮忙解释一下如何修复测试代码以返回一个表?

提前致谢。

小例子:

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;

【问题讨论】:

    标签: postgresql plpgsql


    【解决方案1】:

    给出的例子可以全部替换为RETURN QUERY:

    BEGIN
        RETURN QUERY SELECT y_.y, 'hi' FROM generate_series(1,10,1) AS y_(y)
    END;
    

    这将是一个很多更快。

    一般来说,您应该尽可能避免迭代,而倾向于面向集合的操作。

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

    在这种情况下,您的问题是行 SELECT yr.y, 'hi'; 什么都不做。您假设 SELECT 的隐式目标是输出参数,但事实并非如此。您必须像 @peterm 那样使用 out 参数作为循环变量,使用赋值或使用 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;
    

    【讨论】:

      【解决方案2】:

      一种方法

      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();
      

      结果:

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

      这是一个SQLFiddle演示

      【讨论】:

      • 有用,但如果你能解释一下为什么它会起作用,那就太好了,因为原始发布者显然对输出变量有点困惑。
      【解决方案3】:

      什么@Craig already explained

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

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

      CREATE OR REPLACE FUNCTION test0()
        RETURNS TABLE(y integer, result text) AS
      $func$
      DECLARE
          yr RECORD;
      BEGIN
         FOR y, result IN
            SELECT g, 'text_'::text || g
            FROM   generate_series(1,10) g
         LOOP
            RAISE NOTICE 'Computing %', y;
            RETURN NEXT;
         END LOOP;
      END
      $func$ LANGUAGE plpgsql;

      附加点

      • 不要使用标识符y 两次(作为OUT 参数和列别名),而您可以轻松避免它。那是一把上膛的足枪。有时这是无法避免的,在这种情况下,请始终使用表限定列。

      • 不带参数的最终RETURN 是很好的形式,但完全是可选的。当控制到达最终的END时,自动返回完整的结果。

      • FROM generate_series(1,10) g 中的

        g 自动同时是 表别名列别名,除非给出明确的列别名。它实际上与FROM generate_series(1,10) g(g) 相同。

      【讨论】:

        猜你喜欢
        • 2016-07-07
        • 1970-01-01
        • 2012-10-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-08-29
        • 1970-01-01
        • 2017-05-13
        相关资源
        最近更新 更多