返回多个值并以类似数组的方式填充列

jO.*_*jO. 5 sql postgresql list distinct aggregate-functions

我在 MacOSX 上使用 Postgres 9.3。

我想知道如何返回多个值(取决于某些标准)并使用它们以类似列表/数组的方式填充列?

--DUMMY DATA

CREATE TABLE tbl (
   id VARCHAR(2) PRIMARY KEY
  ,name TEXT
  ,year_born NUMERIC
  ,nationality TEXT
);
INSERT INTO tbl(id, name, year_born, nationality)
VALUES ('A1','Bill',2001,'American')
      ,('B1','Anna',1997,'Swedish')
      ,('A2','Bill',1991,'American')
      ,('B2','Anna',2004,'Swedish')
      ,('B3','Anna',1989,'Swedish')
      ,('A3','Bill',1995,'American');
SELECT * FROM tbl;

id | name | year_born | nationality
---+------+-----------+------------
A1 | Bill |   2001    |  American
B1 | Anna |   1997    |  Swedish
A2 | Bill |   1991    |  American
B2 | Anna |   2004    |  Swedish
B3 | Anna |   1989    |  Swedish
A3 | Bill |   1995    |  American
Run Code Online (Sandbox Code Playgroud)

name, nationality通过 usingSELECT DISTINCT ON子句对列进行池化,如下面的代码所示

CREATE TABLE another_tbl ( name TEXT, nationality TEXT, ids VARCHAR ); 

CREATE FUNCTION f1() RETURNS SETOF another_tbl AS
$$ SELECT DISTINCT ON (name, nationality) name, nationality, id
   FROM tbl
   GROUP BY name, nationality, ID;
$$ LANGUAGE sql

SELECT * FROM f1();

 name | nationality | ids 
------+-------------+-----
 Anna |  Swedish    | B1
 Bill |  American   | A1
Run Code Online (Sandbox Code Playgroud)

所以,这是我不知道如何实现的事情,但我认为这很容易。我希望列ids由与name列中名称对应的所有 id 填充,如下所示。

期望的输出:

 SELECT * FROM f1();

 name | nationality | ids 
------+-------------+-----
 Anna |  Swedish    | B1, B2, B3
 Bill |  American   | A1, A2, A3
Run Code Online (Sandbox Code Playgroud)

更新

发现了ARRAY我与类一起使用VARCHARidsanother_tbl。但是,我收到了一个不匹配的电话,说Final statement returns character varying instead ofcharacter changed[] at column 3

Erw*_*ter 5

如果您想要文本列作为结果,请使用GROUP BY和 聚合函数string_agg()
或者array_agg()构造一个数组。
但丢弃现在多余的DISTINCT ON

SELECT name, nationality, string_agg(id, ',') AS ids
FROM   tbl
GROUP  BY 1, 2
ORDER  BY 1, 2;
Run Code Online (Sandbox Code Playgroud)

RETURNS函数定义的子句必须匹配,就像@ozczecho 建议的那样:

CREATE FUNCTION f1()
  RETURNS TABLE(name text, nationality text, ids text) AS
                                              -- varchar[] for array_agg()
$func$
SELECT t.name, t.nationality, string_agg(t.id, ',') AS ids
FROM   tbl t
GROUP  BY 1, 2
ORDER  BY 1, 2;
$func$ LANGUAGE sql;
Run Code Online (Sandbox Code Playgroud)