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

时间:2009-06-05 10:11:34

标签: 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;

这是如何正确写的?

5 个答案:

答案 0 :(得分: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
$$;

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

要调用此功能,您需要执行以下操作:

select * from storeopeninghours_tostring(1) f(a text, b text, c text);

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

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
$$;

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

答案 1 :(得分:34)

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

假设您要返回三个integer列。

PL / pgSQL函数

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

CREATE OR REPLACE FUNCTION f_foo(open_id numeric)
  RETURNS TABLE (a int, b int, c int) AS
$func$
BEGIN
   -- do something with open_id?
   RETURN QUERY VALUES
     (1,2,3)
   , (3,4,5)
   , (3,4,5);
END
$func$  LANGUAGE plpgsql IMMUTABLE ROWS 3;

呼叫:

SELECT * FROM f_foo(1);

重点

  • 使用RETURNS TABLE定义要返回的临时行类型 或RETURNS SETOF mytbl使用预定义的行类型。

  • 使用RETURN QUERY通过一个命令返回多行。

  • 使用VALUES表达式手动输入多行。这是标准的SQL,并且一直在

  • 对标准参数名称使用参数名称(open_id numeric)而不是ALIAS, which is discouraged。在示例中,不使用参数,只是噪声......

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

  • Function volatility can be IMMUTABLE,因为结果永远不会改变。

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

简单SQL

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

VALUES (1,2,3), (3,4,5), (3,4,5)

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

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

SQL函数

您可以将其包装成简单的SQL function。没有函数参数的示例,因为它没有使用:

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;

答案 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()

答案 3 :(得分:8)

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

见这里: http://wiki.postgresql.org/wiki/Return_more_than_one_row_of_data_from_PL/pgSQL_functions

答案 4 :(得分:6)

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;