将一列的多个结果行连接为一个,按另一列连接

Chi*_*hin 112 sql postgresql aggregate-functions

我有一张这样的桌子

Movie   Actor   
  A       1
  A       2
  A       3
  B       4
Run Code Online (Sandbox Code Playgroud)

我想得到一部电影的名称和该电影中的所有演员,我希望结果是这样的格式:

Movie   ActorList
 A       1, 2, 3
Run Code Online (Sandbox Code Playgroud)

我该怎么做?

Erw*_*ter 187

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

SELECT movie, string_agg(actor, ', ') AS actor_list
FROM   tbl
GROUP  BY 1;
Run Code Online (Sandbox Code Playgroud)

在这种情况下,1in GROUP BY 1是位置参考和快捷方式GROUP BY movie.

string_agg()期望数据类型text作为输入.其他类型需要显式转换(actor::text) - 除非到隐式转换text的定义-这是所有其他字符类型(的情况下varchar,character,"char"),和一些其他类型.

正如isapir评论的那样,你可以ORDER BY在聚合调用中添加一个子句来获取一个排序列表 - 如果你需要它.喜欢:

SELECT movie, string_agg(actor, ', ' ORDER BY actor) AS actor_list
FROM   tbl
GROUP  BY 1;
Run Code Online (Sandbox Code Playgroud)

但是在子查询中对行进行排序通常会更快.看到:

  • 我不知道Postgres支持这样的位置列引用,并且不能想到使用它们的任何好理由,但是否则这就是现场. (3认同)
  • 小提示-如果actor是一个INT,则可能需要actor :: TEXT。至少,在Postgres 9.5中尝试“ string_agg`INT”时出现错误-否则,这正是我所需要的,谢谢! (2认同)
  • 值得注意的是,可选的`ORDER BY`子句可以在delimiter参数之后进入`string_agg`函数,例如`string_agg(actor,','ORDER BY actor DESC)` (2认同)

him*_*056 43

您可以使用以下array_agg功能:

SELECT "Movie",
array_to_string(array_agg(distinct "Actor"),',') AS Actor
FROM Table1
GROUP BY "Movie";
Run Code Online (Sandbox Code Playgroud)

结果:

| MOVIE | ACTOR |
-----------------
|     A | 1,2,3 |
|     B |     4 |
Run Code Online (Sandbox Code Playgroud)

看到这个SQLFiddle

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

  • 为SQLFiddle +1,这是一个很棒的工具 (4认同)