SQL如何将行“收集”到一行

时间:2018-05-28 01:52:08

标签: sql postgresql

假设我有一个电子邮件功能,我需要选择电子邮件的收件人。

users表格包含以下列:idfull_name

emails表包含以下列:idsubjectbodysender_idrecipient_id

伪代码是

SELECT
  e.id AS email_id,
  e.subject AS email_subject,
  u_sender.full_name AS sender_name,
  u_recipient.full_name AS recipient_name
FROM emails e
LEFT JOIN users u_sender
  ON e.sender_id = u_sender.id
LEFT JOIN users u_recipient
  ON e.recipient_id = u_recipient.id

这将返回如下内容:

| email_id | email_subject | sender_name | recipient_name |
| 1 |你好 |约翰 |史蒂夫|
| 1 |你好 |约翰 |马克|
| 1 |你好 |约翰 |彼得|

相反,有没有办法得到类似的东西:
| email_id | email_subject | sender_name | recipient_name |
| 1 |你好 |约翰 | [史蒂夫,彼得,马克] |

请注意,它们具有相同的email_id,因为我的应用程序可以将电子邮件发送给多个收件人。

我找到a similar question,但解决方案是apache-exclusive。

我还发现了一个使用XML PATH here的响应,但它适用于SQL Server 2005.我正在使用postgres。

提前致谢。

2 个答案:

答案 0 :(得分:2)

PostgreSQL 9提供string_agg聚合函数,将多个值展平为单个字符串。在您的示例中,它将是string_agg(u_recipient.full_name, ',')以及合适的group by

select
  e.id email_id,
  e.subject email_subject,
  u_sender.full_name sender_name,
  string_agg(u_recipient.full_name, ',') recipient_name
from emails e
left join users u_sender
  on e.sender_id = u_sender.id
left join users u_recipient
  on e.recipient_id = u_recipient.id
group by email_id, email_subject, sender_name

答案 1 :(得分:0)

将GROUP BY子句与email_id,email_subject,sender_name一起使用,并调用STRING_AGG(recipient_name,',')

你会有这样的事情:

SELECT email_id, email_subject, sender_name, string_agg(recipient_name, ',') FROM test GROUP BY email_id, email_subject, sender_name

使用您的查询:

WITH X AS 
(
SELECT
  e.id AS email_id,
  e.subject AS email_subject,
  u_sender.full_name AS sender_name,
  u_recipient.full_name AS recipient_name
FROM emails e
LEFT JOIN users u_sender
  ON e.sender_id = u_sender.id
LEFT JOIN users u_recipient
  ON e.recipient_id = u_recipient.id
)
SELECT email_id, email_subject, sender_name, string_agg(recipient_name, ',') FROM X GROUP BY email_id, email_subject, sender_name;