4

我在 PostgreSQL 文档中找不到任何内容来说明如何声明记录或行,同时声明元组结构。如果你没有定义你的元组结构,你会得到错误“尚未分配记录的元组结构是不确定的”。

这就是我现在正在做的事情,效果很好,但必须有更好的方法来做到这一点。

CREATE OR REPLACE FUNCTION my_func()
  RETURNS TABLE (
    "a" integer,
    "b" varchar
  ) AS $$
DECLARE r record;
BEGIN

CREATE TEMP TABLE tmp_t (
    "a" integer,
    "b" varchar
);
-- Define the tuple structure of r by SELECTing an empty row into it.
-- Is there a more straight-forward way of doing this?
SELECT * INTO r
FROM tmp_t;

-- Now I can assign values to the record.
r.a := at.something FROM "another_table" at
       WHERE at.some_id = 1;

-- A related question is - how do I return the single record 'r' from
-- this function?
-- This works:
RETURN QUERY
SELECT * FROM tmp_t;

-- But this doesn't:
RETURN r;
-- ERROR:  RETURN cannot have a parameter in function returning set

END; $$ LANGUAGE plpgsql;
4

3 回答 3

14

您将返回SETOF值的语法与返回单行或值的语法混合在一起。

- 一个相关的问题是 - 我如何从

当你用 声明一个函数时RETURNS TABLE,你必须RETURN NEXT在主体中使用来返回一行(或标量值)。如果你想使用一个record变量,它必须匹配返回类型。请参阅下面的代码示例。

返回单个值或行

如果您只想返回单行,则不需要未定义类型的记录。@Kevin 已经展示了两种方法。我将添加一个带有OUT参数的简化版本:

CREATE OR REPLACE FUNCTION my_func(OUT a integer, OUT b text)
   AS
$func$
BEGIN
   a := ...;
   b := ...;
END
$func$ LANGUAGE plpgsql;

您甚至不需要RETURN;在函数体中添加,声明OUT参数的值将在函数末尾自动返回 -NULL对于任何尚未分配的参数。
而且您不需要声明RETURNS RECORD,因为从OUT参数中已经很清楚了。

返回一组行

如果您实际上想要返回行(包括 0 或 1 行的可能性),您可以将返回类型定义为RETURNS...

  • SETOF some_type,其中some_type可以是任何已注册的标量或复合类型。

  • TABLE (col1 type1, col2 type2)- ad-hoc 行类型定义。

  • SETOF record加上OUT参数来定义列名和类型。
    100% 相当于RETURNS TABLE

  • SETOF record无需进一步定义。但是返回的行是未定义的,您需要在每次调用时包含一个列定义列表(参见示例)。

关于记录类型的手册

记录变量类似于行类型变量,但它们没有预定义的结构。它们采用在 SELECT 或 FOR 命令期间分配的行的实际行结构。

还有更多,请阅读手册。

可以使用记录变量而不分配已定义的类型,甚至可以返回此类未定义的记录:

CREATE OR REPLACE FUNCTION my_func()
  RETURNS SETOF record AS
$func$
DECLARE
    r record;
BEGIN
    r := (1::int, 'foo'::text); RETURN NEXT r; -- works with undefined record
    r := (2::int, 'bar'::text); RETURN NEXT r;
END
$func$ LANGUAGE plpgsql;

称呼:

SELECT * FROM my_func() AS x(a int, b text);

但这非常笨拙,因为您必须在每次调用时提供列定义列表。它通常可以用更优雅的东西代替:

  • 如果您在创建函数时知道类型,请立即(RETURNS TABLE或朋友)声明它。

CREATE OR REPLACE FUNCTION my_func()
  RETURNS SETOF tbl_or_type AS
$func$
DECLARE
    r tbl_or_type;
BEGIN
    SELECT INTO tbl_or_type  * FROM tbl WHERE id = 10;
    RETURN NEXT r;  -- type matches

    SELECT INTO tbl_or_type  * FROM tbl WHERE id = 12;
    RETURN NEXT r;

    -- Or simpler:
    RETURN QUERY
    SELECT * FROM tbl WHERE id = 14;
END
$func$ LANGUAGE plpgsql;

您的问题不清楚您到底需要什么。

于 2012-08-11T04:39:54.853 回答
4

可能有一些方法可以避免显式类型声明,但我能想到的最好的方法是:

CREATE TYPE my_func_return AS (
    a integer,
    b varchar
  );

CREATE OR REPLACE FUNCTION my_func()
  RETURNS my_func_return AS $$
DECLARE
  r my_func_return;
BEGIN
  SELECT 1, 'one' INTO r.a, r.b;
  RETURN r;
END; $$ LANGUAGE plpgsql;

哦,我差点忘了最简单的方法:

CREATE OR REPLACE FUNCTION my_func2(out a int, out b text)
  RETURNS RECORD AS $$
BEGIN
  SELECT 1, 'one' INTO a, b;
  RETURN;
END; $$ LANGUAGE plpgsql;
于 2012-08-10T19:42:55.023 回答
1

OUT使用参数比使用记录要容易得多。如果迭代地构建一组记录(表),请使用RETURN NEXT. 如果从查询生成,请使用RETURN QUERY. 看:

https://stackoverflow.com/a/955289/398670

和:

http://www.postgresql.org/docs/current/static/plpgsql-declarations.html http://www.postgresql.org/docs/current/static/sql-createfunction.html http://www.postgresonline。 com/journal/archives/129-Use-of-OUT-and-INOUT-Parameters.html

思考:

CREATE OR REPLACE FUNCTION my_func(OUT a integer, OUT b varchar) RETURNS SETOF RECORD AS $$
BEGIN
    -- Assign a and b, RETURN NEXT, repeat. when done, RETURN.
END;
$$ LANGUAGE 'plpgsql';  
于 2012-08-11T09:57:41.223 回答