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

时间:2013-11-20 00:52:53

标签: sql list postgresql 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

我使用name, nationality子句汇总到列SELECT 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

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

期望的输出:

 SELECT * FROM f1();

 name | nationality | ids 
------+-------------+-----
 Anna |  Swedish    | B1, B2, B3
 Bill |  American   | A1, A2, A3

更新

ARRAY中找到VARCHARids课一起用于another_tbl列的Final statement returns character varying instead of。但是,我收到了一个不匹配的来电,说at column 3字符变化[] {{1}}。

3 个答案:

答案 0 :(得分:3)

如果您希望将文本列作为结果,请使用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;

函数定义的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;

答案 1 :(得分:1)

我相信你应该改变:

RETURNS SETOF another_tbl

为:

RETURNS TABLE(name TEXT, nationality TEXT, ids VARCHAR[])

答案 2 :(得分:0)

好的,它可以使用array_agg函数。

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

SELECT * FROM f();

name | nationality |    ids     
-----+-------------+-----------
Anna | Swedish     | {B1,B2,B3}
Bill | American    | {A1,A2,A3}

将函数array_to_string添加到array_agg(id)后,我们得到了所需的输出

name | nationality |   ids    
-----+-------------+---------
Anna | Swedish     | B1,B2,B3
Bill | American    | A1,A2,A3