如何在 PL/pgSQL 中返回多行记录

hky*_*404 17 postgresql plpgsql postgresql-9.5

我正在尝试使用 RECORD 数据类型返回多个记录,有没有一种方法可以附加到 RECORD 并在每次迭代时向该 RECORD 添加/附加一个新值。

也就是说,我要追加到rec使rec成为一组行,当循环结束,我可以只返回在我的函数结束。目前,我正在这样做 -

SELECT temp_table.col1, temp_table.col2, temp_table.col3
      INTO rec
      FROM temp_table
      WHERE temp_table.col3 = false;
Run Code Online (Sandbox Code Playgroud)

我的完整代码在这里:

CREATE OR REPLACE FUNCTION validation()
  RETURNS RECORD AS $$
DECLARE
        rec RECORD;
        temp_row RECORD;
BEGIN

  CREATE TEMPORARY TABLE temp_table (col1 TEXT, col2 INTEGER, col3 BOOLEAN) ON COMMIT DROP;

  FOR temp_row IN SELECT * FROM staging.validation
  LOOP

    RAISE NOTICE 'sql: %', temp_row.sql;

    EXECUTE format('INSERT INTO temp_table %s', temp_row.sql);

    IF (SELECT DISTINCT temp_table.col3 FROM temp_table WHERE temp_table.col3 = false)=false THEN
      RAISE NOTICE 'there is a false value';

      SELECT temp_table.col1, temp_table.col2, temp_table.col3
      INTO rec
      FROM temp_table
      WHERE temp_table.col3 = false;
    END IF;


  END LOOP;
  RETURN rec;
END; $$
LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

后电流输出 SELECT validation();

validation
(crea_ddf,8095,f)
Run Code Online (Sandbox Code Playgroud)

期望输出

validation
(crea_ddf,8095,f)
(some_source_system,some_count,f)
(some_other_source_system,some_count,f)
(.....)
Run Code Online (Sandbox Code Playgroud)

Dan*_*ité 17

该函数需要返回一个SETOF RECORD而不是每行RECORD一个RETURN NEXT而不是一个RETURN,如下所示:

CREATE FUNCTION test() RETURNS SETOF RECORD AS $$
DECLARE
 rec record;
BEGIN
  select 1,2 into rec;
  return next rec;

  select 3,4 into rec;
  return next rec;
END $$ language plpgsql;
Run Code Online (Sandbox Code Playgroud)

呼叫者:

=> select * from test() as x(a int ,b int) ;
 | 乙
---+---
 1 | 2
 3 | 4
(2 行)

请注意,SQL 是强类型和静态类型的,RECORD伪类型很难使用。
通常,从一开始就使用具有每个列的名称和类型的完整定义的复合类型,无论TABLE(...)是匿名类型的语法还是CREATE TYPE持久命名类型的语法,都不会那么麻烦。


kli*_*lin 11

如果要从函数返回多条记录,请使用setof recordand return next rec,例如:

create or replace function test_function()
    returns setof record 
    language plpgsql as $$
declare
    rec record;
begin
    for rec in
        select i, format('str%s', i), i/2*2 = i
        from generate_series(1, 3) i
    loop
        return next rec;
    end loop;
end $$;
Run Code Online (Sandbox Code Playgroud)

这样的函数需要在带有列定义列表的 FROM 子句中调用:

select test_function(); -- NO

ERROR:  set-valued function called in context that cannot accept a set  

select * from test_function();  -- NO

ERROR:  a column definition list is required for functions returning "record"

select * from test_function() as (id int, str text, is_even boolean);

 id | str  | is_even 
----+------+---------
  1 | str1 | f
  2 | str2 | t
  3 | str3 | f
(3 rows)
Run Code Online (Sandbox Code Playgroud)

更好的选择是使用returns table(...)return query

drop function if exists test_function();
create or replace function test_function()
    returns table (id int, str text, is_even boolean)
    language plpgsql as $$
begin
    return query
        select i, format('str%s', i), i/2*2 = i
        from generate_series(1, 3) i;
    -- you can use return query multiple times
    -- or assign values to columns
    -- and return the row:
    id = 100;
    str = 'extra';
    is_even = true;
    return next; -- without a parameter
end $$;
Run Code Online (Sandbox Code Playgroud)

用法:

select test_function(); -- possible but rather impractical

 test_function 
---------------
 (1,str1,f)
 (2,str2,t)
 (3,str3,f)
 (100,extra,t)
(4 rows)

select * from test_function();

 id  |  str  | is_even 
-----+-------+---------
   1 | str1  | f
   2 | str2  | t
   3 | str3  | f
 100 | extra | t
(4 rows)
Run Code Online (Sandbox Code Playgroud)