SQL多表查询去重并合并指定列数据的实现方法咨询
嘿,我明白你的问题了——你通过JOIN和UNION拉取多表数据后,出现了重复ID的行,想要把同一ID对应的Exams内容合并到一行里,而且没法用createDate去重,因为日期也重复对吧?
你原来的查询用了DISTINCT加UNION ALL,但DISTINCT是针对整行数据去重的,只要某一行的任何一列和其他行不一样,就会被保留,所以没法解决同一ID但Exams不同的重复问题。要实现合并Exams的需求,核心思路是先把所有需要的数据整合到一起,再按ID分组,用字符串聚合函数把Exams列合并起来。
下面分不同数据库给你具体的解决方案:
针对SQL Server的写法
先用CTE把UNION ALL后的所有数据整合,再按ID和其他非聚合列分组,用STRING_AGG合并Exams:
WITH CombinedData AS ( -- 第一部分:calsses与documents的关联数据 SELECT table1.ID, table1.ClassName, -- 替换成table1实际的列名,不要用* table1.Teacher, table2.Date, table2.DocumentName, table1.Exams AS ExamContent -- 单独提取Exams,方便后续聚合 FROM calsses table1 INNER JOIN documents table2 ON table1.ID = table2.ID UNION ALL -- 第二部分:exams与documents的关联数据 SELECT table3.ID, table3.ClassName, -- 必须和上面的列顺序、数据类型完全一致 table3.Teacher, table2.Date, table2.DocumentName, table3.Exams AS ExamContent FROM exams table3 INNER JOIN documents table2 ON table3.ID = table2.ID ) SELECT ID, ClassName, Teacher, Date, DocumentName, STRING_AGG(ExamContent, ', ') AS Exams -- 用逗号分隔多个考试内容,可自定义分隔符 FROM CombinedData GROUP BY ID, ClassName, Teacher, Date, DocumentName -- 所有非聚合列都要明确列出 ORDER BY Date DESC; -- 保持你原有的排序需求
针对MySQL的写法
MySQL用GROUP_CONCAT函数实现字符串聚合,用子查询替代CTE:
SELECT ID, ClassName, Teacher, Date, DocumentName, GROUP_CONCAT(ExamContent SEPARATOR ', ') AS Exams FROM ( SELECT table1.ID, table1.ClassName, table1.Teacher, table2.Date, table2.DocumentName, table1.Exams AS ExamContent FROM calsses table1 INNER JOIN documents table2 ON table1.ID = table2.ID UNION ALL SELECT table3.ID, table3.ClassName, table3.Teacher, table2.Date, table2.DocumentName, table3.Exams AS ExamContent FROM exams table3 INNER JOIN documents table2 ON table3.ID = table2.ID ) AS CombinedData GROUP BY ID, ClassName, Teacher, Date, DocumentName ORDER BY Date DESC;
针对PostgreSQL的写法
PostgreSQL同样支持STRING_AGG,写法和SQL Server的CTE方式一致:
WITH CombinedData AS ( SELECT table1.ID, table1.ClassName, table1.Teacher, table2.Date, table2.DocumentName, table1.Exams AS ExamContent FROM calsses table1 INNER JOIN documents table2 ON table1.ID = table2.ID UNION ALL SELECT table3.ID, table3.ClassName, table3.Teacher, table2.Date, table2.DocumentName, table3.Exams AS ExamContent FROM exams table3 INNER JOIN documents table2 ON table3.ID = table2.ID ) SELECT ID, ClassName, Teacher, Date, DocumentName, STRING_AGG(ExamContent, ', ') AS Exams FROM CombinedData GROUP BY ID, ClassName, Teacher, Date, DocumentName ORDER BY Date DESC;
几个关键注意点:
- 务必把
table1.*、table3.*换成具体的列名,不能用通配符*,因为GROUP BY要求明确列出所有非聚合的列,规范写法必须列全。 - 保证
UNION ALL前后两部分的列数、顺序、数据类型完全一致,否则会出现数据类型不匹配的错误。 - 如果同一ID下的其他列(比如ClassName、Teacher)存在不同的值,GROUP BY后会把这些不同的组合分成多行。如果不符合需求,可以用
MAX(ClassName)、MIN(Teacher)这类聚合函数统一这些列的值。 - 分隔符可以按需修改,比如换成
'; '或者' | '都可以。
内容的提问来源于stack exchange,提问作者IT Developer
相关产品推荐
相关产品推荐

