声明PL / pgSQL中记录的元组结构

时间:2012-08-10 18:50:36

标签: postgresql plpgsql postgresql-9.1

我在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;

3 个答案:

答案 0 :(得分:12)

您正在混合syntax for returning SETOF values with syntax for returning a single row or value

  

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

返回单个记录'r'

使用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) - 临时行类型定义。

  • SETOF recordOUT个参数来定义列名称和类型 100%相当于RETURNS TABLE

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

The manual about the record type

  

记录变量与行类型变量类似,但它们具有 no   预定义的结构。它们采用了实际的行结构   在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;

你的问题不清楚你究竟需要什么。

答案 1 :(得分:3)

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

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;

答案 2 :(得分: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';