6

我正在编写一个 PL/pgSQL 存储过程,它将返回一组记录;每条记录都包含现有表的所有字段(称为零售商,它有两个字段:retailer_key 和retailer_name)。当然,这有效:

CREATE FUNCTION proc_Find_retailers
 (IN p_Store_key INT)
   RETURNS SETOF Retailer
   AS $$ ...`

现在我想更新 sp 以便它在每个返回记录的“末尾”返回两个额外的字段。我可以做一些事情,例如:

CREATE FUNCTION proc_Find_store
 (IN p_Store_key INT)
   RETURNS TABLE (
      retailer_key int,
      retailer_name varchar(50),
      addl_field_1 int,
      addl_field_2 double precision)
   AS $$ ...

在现实世界中,我的 Retailer 表有 50 个字段(不是我的示例中的两个),因此在 RETURNS TABLE 子句中枚举所有这些字段很乏味。是否有任何捷径,所以我可能会说这样的话(我意识到我在这里编造的东西在语法上是非法的,但我这样做是为了给你我正在寻找的东西的味道):

CREATE FUNCTION proc_Find_store
 (IN p_Store_key INT)
   RETURNS (SETOF Store,
      addl_field_1 int,
      addl_field_2 double precision)
   AS $$ ...
4

1 回答 1

8

可以将一整行作为复合类型返回并添加更多:

CREATE OR REPLACE FUNCTION f_rowplus()
  RETURNS TABLE (rec demo, add_int int, add_txt text) AS
$func$
SELECT d, 5, 'baz'::text FROM demo d;
$func$  LANGUAGE sql;

但是,当您使用简单的调用时:

SELECT * FROM f_rowplus();

您从表中获取行demo作为单独的复合类型。您必须致电:

SELECT (rec).*,  add_int, add_txt FROM f_rowplus();

获取所有单独的列。需要括号。

Postgres 在这里有点不一致。如果您使用以下命令创建函数:

CREATE OR REPLACE FUNCTION f_row2()
  RETURNS TABLE (rec demo) AS
...

然后复合类型demo被静默转换为单独的列(分解)。没有到原始复合类型的链接仍然存在。您根本无法引用声明的输出列rec,因为它已被分解类型的列替换。此调用将导致错误消息:

SELECT rec FROM f_row2();  -- error!

同样在这里:

CREATE OR REPLACE FUNCTION f_row3(OUT rec demo)
  RETURNS SETOF demo AS
...

但是,只要您添加更多OUT列,复合类型就会保留为已声明(未分解),您可以:

SELECT rec FROM f_rowplus();

与第一个功能。

db<>fiddle here - 演示所有变体
Old sqlfiddle

旁白

当使用返回列表中多列的函数FROM(作为表函数)并在SELECT列表中分解时,如下所示:

SELECT (rec).* FROM f_rowplus();

...该函数仍然只评估一次- 在列表中直接调用分解,如下所示:SELECT

SELECT (f_rowplus()).*;  -- also: different result

... 将为返回类型中的每一列计算一次。看:

Postgres 14或更高版本中,您还可以使用标准 SQL 语法:

CREATE OR REPLACE FUNCTION f_rowplus_std()
  RETURNS TABLE (rec demo, add_int int, add_txt text)
  LANGUAGE sql PARALLEL SAFE
BEGIN ATOMIC
SELECT d, 5, 'baz'::text FROM demo d;
END;

看:

于 2013-07-24T05:16:25.697 回答