41

我需要一个 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;

这个怎么写正确?

4

6 回答 6

43

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

假设您要返回三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;

在 Postgres 9.6 或更高版本中,您还可以添加PARALLEL SAFE.

称呼:

SELECT * FROM f_foo();

要点

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

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

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

  • 如果您确实需要参数,请使用参数名称(open_id numeric)而不是ALIAS,这是不鼓励的。在示例中,没有使用参数,只是噪音......

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

  • 函数的波动性可以是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 函数

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;
于 2013-06-22T03:41:52.670 回答
42

(这都是用 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
$$;

(不太清楚为什么需要额外的 ::text 强制转换......'1'默认情况下可能是一个varchar?)

于 2009-06-05T10:50:05.897 回答
25

我在我的函数中使用了很多临时表。您需要在数据库上创建一个返回类型,然后创建一个该类型的变量来返回。下面是执行此操作的示例代码。

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()
于 2009-06-05T11:46:05.207 回答
8
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;
于 2009-06-05T10:59:27.920 回答
8

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

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

于 2010-11-30T01:05:48.860 回答
0

从 PostgreSQL 11 开始,您可以使用procedure

CREATE OR REPLACE PROCEDURE f_foo()  LANGUAGE plpgsql
   AS
$$
BEGIN
drop table if exists foo cascade;
create temp table  IF NOT EXISTS foo (a int, b int, c int);
insert into foo VALUES
  (1,2,3)
, (3,4,5)
, (3,4,5)
;
END
$$;

当你想要一个临时表时,你可以调用它。

call f_foo();

如果存在,它将删除表foo 。

于 2021-12-07T09:22:42.610 回答