根据唯一标识符列合并单独的行

时间:2017-06-23 14:37:18

标签: sql

我有2个表,一个有人员数据,另一个有志愿者查询代码:

Person Table
| ID |  UID  | First | Last | VolCode | VolYear
| 00 | 09123 | John  | Doe  | A01     | 2016
| 01 | 09123 | John | Doe   | A02     | 2016
| 02 | 09123 | John | Doe   | A03     | 2016

-

Vol Table
| ID | VolCode | Name      |
| 00 | A01     | Something |
| 01 | A02     | Something |
| 02 | A03     | Something |

期望的结果:

Results
| p.UID | p.First | p.Last | v.VolCodes  | v.volYear   |
| 09123 | John    | Does   | A01,A02,A03 | 2016        |

在SQL中是否有办法创建一个包含连续的VolCode列表的列,例如所需的结果?

1 个答案:

答案 0 :(得分:0)

取决于您的DBMS。

PostgreSQL 聚合函数称为array_agg

SELECT a, array_agg(b) 
FROM (VALUES (1, 'abc'), (1, 'def'), (1, 'xyz')) t ( a, b ) 
GROUP BY a;

给出了

 a |   array_agg   
---+---------------
 1 | {abc,def,xyz}

MySQL / MariaDB 聚合函数称为GROUP_CONCAT。 可能是这样的:

SELECT a, group_concat(b) 
FROM (VALUES (1, 'abc'), (1, 'def'), (1, 'xyz')) t ( a, b ) 
GROUP BY a;

您的预期结果似乎只是使用了第一个表格。您确定不会引用person.volCode引用vol.id的外键引用吗?问题是如何将行汇总在一起 - 您是GROUP BY person.uid吗?到person.year? 您的示例的查询可能是(仅使用person表):

SELECT uid, first, last, array_agg(volCode) AS "volCodes", volYear 
FROM person  
GROUP BY uid, first, last, volYear;

您应该知道,volCodes列中没有原子值(不是第一范式),您无法轻松继续处理此列。在聚合之前,您有3行,您可以使用WHERE子句轻松过滤。汇总后,过滤部分汇总值volCodes要困难得多。此外,GROUP BY字段上的索引可能会加快分组速度。我们仍然不知道应该聚合哪些值。我在这里假设所有4列(uid, first, last, volYear) - 它可能会有所不同 - 这取决于你。

如果您只想GROUP BY uid,则列first, last, volYear是多值的。您也可以array_agg像这样

SELECT uid, 
       array_agg(first), 
       array_agg(last), 
       array_agg(volCode) AS "volCodes", 
       array_agg(volYear) 
FROM person  
GROUP BY uid;

将携带相同的firstname三次(因为您的示例表数据)。

或者你可以用

选择最小值或其他东西
SELECT uid, 
       MIN(first), -- chooses the alphabetically ordered firstname
       MIN(last), 
       array_agg(volCode) AS "volCodes", 
       MIN(volYear) 
FROM person  
GROUP BY uid;

这可能不是你想要的。