将一个列的多个结果行合并为一个,按另一列进行分组。

229

我有一个类似这样的表格:

电影 演员
A 1
A 2
A 3
B 4

我想得到一部电影的名称以及所有出演该电影的演员,并且我希望结果的格式如下:

电影 演员列表
A 1,2,3

我应该怎么做呢?


然后检查这个:https://dev59.com/0Gct5IYBdhLWcg3wFpi1 - Asken
2个回答

399

使用聚合函数string_agg() (Postgres 9.0或更高版本),更加简单:

SELECT movie, string_agg(actor, ', ') AS actor_list
FROM   tbl
GROUP  BY 1;

GROUP BY 1 中的 1 是一个位置引用,也是在这种情况下 GROUP BY movie 的一种快捷方式。

string_agg() 函数期望输入数据类型为 text。其他类型需要显式转换(actor::text) - 除非已定义隐式转换为 text - 这对于所有其他字符串类型(varcharcharactername等)和某些其他类型是适用的。

正如 isapir 评论的,您可以在聚合调用中添加 ORDER BY 子句以获取有序列表 - 如果您需要的话。例如:

SELECT movie, string_agg(actor, ', ' <b>ORDER BY actor</b>) AS actor_list
FROM   tbl
GROUP  BY 1;

但通常在子查询中对行进行排序速度更快。请参见:


6
我不知道Postgres支持这样的位置列引用,也想不出使用它们的好理由,但是除此之外,这个表述是正确的。 - IMSoP
1
@IMSoP:这只是我偶然加入的一种语法便利。一个很好的使用案例是在SELECT列表中或使用动态SQL中的复杂表达式。 - Erwin Brandstetter
2
小提示 - 如果 actor 是一个 INT,可能需要使用 actor::TEXT。在 Postgres 9.5 中尝试使用 string_agg 聚合 INT 时会出现错误 - 但除此之外,这正是我所需要的,谢谢! - dwanderson
1
@Chris:可能是与您的客户端设置有关,与查询无关。请参考:https://stackoverflow.com/a/23568429/939860 - Erwin Brandstetter
4
值得注意的是,在分隔符参数之后,string_agg函数可以加上一个可选的 ORDER BY 子句,例如:string_agg(actor, ', ' ORDER BY actor DESC) - isapir
显示剩余6条评论

88
您可以使用array_agg函数进行相关操作:
SELECT "Movie",
array_to_string(array_agg(distinct "Actor"),',') AS Actor
FROM Table1
GROUP BY "Movie";

结果:

电影 演员
A 1,2,3
B 4

查看此SQLFiddle

更多信息,请参见9.18. 聚合函数


string_agg和array_agg有什么区别? - mercury
1
@mercury,string-agg 会生成字符串类型的字段,即将 string_agg 的所有参数元素连接成单个字符串;array-agg 会生成数组类型的字段,例如字符串数组,即 array_agg 的所有参数元素将保持其原始类型。 - Thatislove

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接