从函数返回setof记录(虚拟表)

Dav*_*vid 37 sql postgresql stored-procedures plpgsql

我需要一个Postgres函数来返回一个带有自定义内容的虚拟表(就像在Oracle中一样).该表将有3列和未知行数.

我在互联网上找不到正确的语法.

想象一下:

CREATE OR REPLACE FUNCTION "public"."storeopeninghours_tostring" (numeric)
  RETURNS setof record AS
DECLARE
  open_id ALIAS FOR $1;
  returnrecords setof record;
BEGIN
  insert into returnrecords('1', '2', '3');
  insert into returnrecords('3', '4', '5');
  insert into returnrecords('3', '4', '5');
  RETURN returnrecords;
END;
Run Code Online (Sandbox Code Playgroud)

这怎么写的正确?

Erw*_*ter 38

所有当前存在的答案都已过时或开始时效率低下.

假设您要返回三integer列.

PL/pgSQL函数

以下是使用现代PL/pgSQL(PostgreSQL 8.4或更高版本)的方法:

CREATE OR REPLACE FUNCTION f_foo() -- (open_id numeric) -- parameter not used
  RETURNS TABLE (a int, b int, c int) AS
$func$
BEGIN
RETURN QUERY VALUES
  (1,2,3)
, (3,4,5)
, (3,4,5)
;
END
$func$  LANGUAGE plpgsql IMMUTABLE ROWS 3;
Run Code Online (Sandbox Code Playgroud)

呼叫:

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

主要观点

  • 使用PARALLEL SAFE来定义一个特设排式返回.
    或者RETURNS TABLE使用预定义的行类型.

  • 用于使用RETURNS SETOF mytbl一个命令返回多行.

  • 使用RETURN QUERY表达式手动输入多行.这是标准的SQL和一直围绕永远.

  • 使用参数名称VALUES代替(open_id numeric),不鼓励使用标准参数名称.在示例中,参数未使用,只是噪音......

  • 无需双引号完全合法的标识符.双引号只需要强制使用其他非法名称(混合大小写,非法字符或保留字).

  • 功能波动可以是ALIAS,因为结果永远不会改变.

  • IMMUTABLE是可选的,但由于我们知道返回了多少行,我们不妨将其声明为Postgres.可以帮助查询计划员选择最佳计划.

简单的SQL

对于这样的简单情况,您可以使用纯SQL语句:

VALUES (1,2,3), (3,4,5), (3,4,5)
Run Code Online (Sandbox Code Playgroud)

或者,如果您希望(或有)定义特定的列名称和类型:

SELECT *
FROM  (
   VALUES (1::int, 2::int, 3::int)
        , (3, 4, 5)
        , (3, 4, 5)
   ) AS t(a, b, c);
Run Code Online (Sandbox Code Playgroud)

SQL函数

您可以将其包装到一个简单的SQL函数中.没有函数参数的示例,因为它没有使用:

CREATE OR REPLACE FUNCTION f_foo()
   RETURNS TABLE (a int, b int, c int) AS
$func$
   VALUES (1, 2, 3)
        , (3, 4, 5)
        , (3, 4, 5);
$func$  LANGUAGE sql IMMUTABLE ROWS 3;
Run Code Online (Sandbox Code Playgroud)


ara*_*nid 37

(这都是用postgresql 8.3.7测试的 - 你有早期版本吗?只看你使用"ALIAS FOR $ 1")

CREATE OR REPLACE FUNCTION storeopeninghours_tostring(numeric)
 RETURNS SETOF RECORD AS $$
DECLARE
 open_id ALIAS FOR $1;
 result RECORD;
BEGIN
 RETURN QUERY SELECT '1', '2', '3';
 RETURN QUERY SELECT '3', '4', '5';
 RETURN QUERY SELECT '3', '4', '5';
END
$$;
Run Code Online (Sandbox Code Playgroud)

如果要返回记录或行变量(而不是查询结果),请使用"RETURN NEXT"而不是"RETURN QUERY".

要调用该函数,您需要执行以下操作:

select * from storeopeninghours_tostring(1) f(a text, b text, c text);
Run Code Online (Sandbox Code Playgroud)

因此,您必须定义您希望函数的输出行模式在查询中的内容.为避免这种情况,您可以在函数定义中指定输出变量:

CREATE OR REPLACE FUNCTION storeopeninghours_tostring(open_id numeric, a OUT text, b OUT text, c OUT text)
 RETURNS SETOF RECORD LANGUAGE 'plpgsql' STABLE STRICT AS $$
BEGIN
 RETURN QUERY SELECT '1'::text, '2'::text, '3'::text;
 RETURN QUERY SELECT '3'::text, '4'::text, '5'::text;
 RETURN QUERY SELECT '3'::text, '4'::text, '5'::text;
END
$$;
Run Code Online (Sandbox Code Playgroud)

(不太确定为什么extra :: text强制转换是必需的...'1'默认情况下是varchar?)

  • select*from storeopeninghours_tostring(1)f(text,b text,c text); 什么是"f("做什么?我尝试用d和其他角色替换f,它们似乎都有效...... (2认同)

小智 23

我在我的函数中使用了临时表.您需要在数据库上创建返回类型,然后创建要返回的该类型的变量.下面是示例代码.

CREATE TYPE storeopeninghours_tostring_rs AS
(colone text,
 coltwo text,
 colthree text
);

CREATE OR REPLACE FUNCTION "public"."storeopeninghours_tostring" () RETURNS setof storeopeninghours_tostring_rs AS
$BODY$
DECLARE
  returnrec storeopeninghours_tostring_rs;
BEGIN
    BEGIN 
        CREATE TEMPORARY TABLE tmpopeninghours (
            colone text,
            coltwo text,
            colthree text
        );
    EXCEPTION WHEN OTHERS THEN
        TRUNCATE TABLE tmpopeninghours; -- TRUNCATE if the table already exists within the session.
    END;
    insert into tmpopeninghours VALUES ('1', '2', '3');
    insert into tmpopeninghours VALUES ('3', '4', '5');
    insert into tmpopeninghours VALUES ('3', '4', '5');

    FOR returnrec IN SELECT * FROM tmpopeninghours LOOP
        RETURN NEXT returnrec;
    END LOOP;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;


select * from storeopeninghours_tostring()
Run Code Online (Sandbox Code Playgroud)


小智 8

对于那些已经登陆这里寻找MSSQL相当于创建临时表并将其记录转储为返回的人...在PostgreSQL中不存在:( - 你必须定义返回类型.有两种方法可以做这,在创建函数时或在创建查询时.

请看:http: //wiki.postgresql.org/wiki/Return_more_than_one_row_of_data_from_PL/pgSQL_functions


小智 7

CREATE OR REPLACE FUNCTION foo(open_id numeric, OUT p1 varchar, OUT p2 varchar, OUT p3 varchar) RETURNS SETOF RECORD AS $$
BEGIN
  p1 := '1'; p2 := '2'; p3 := '3';
  RETURN NEXT; 
  p1 := '3'; p2 := '4'; p3 := '5';
  RETURN NEXT; 
  p1 := '3'; p2 := '4'; p3 := '5';
  RETURN NEXT; 
  RETURN;
END;
$$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)