SQL新手求助:能否用Union合并order_id=1的两条差异记录?
解决同order_id多条记录的合并问题
嘿,作为SQL新手碰到这种同订单ID但联系人不同的情况太常见啦,我来给你详细讲讲怎么处理~
首先先纠正你对UNION的小误解:UNION其实是用来合并结构完全相同的数据集,它会自动去重;如果不想去重就用UNION ALL。它并不是用来合并同ID下的不同字段的,你的需求更适合用分组聚合或者特定场景下的自JOIN,下面给你具体的方案:
方法一:分组+字符串聚合(最通用推荐)
因为你的数据里,同order_id的order_location和order_value都是一致的,我们可以把这三个字段作为分组依据,然后用字符串聚合函数把同一个组里的order_contact合并成一个字段。
先给你模拟你的数据表(方便测试):
CREATE TABLE orders ( order_id INT, order_contact VARCHAR(50), order_location VARCHAR(50), order_value INT ); INSERT INTO orders VALUES (1, 'Tom''s Business', '123 Street', 100), (1, 'John''s Management', '123 Street', 100), (2, 'Tim''s Business', '543 Avenue', 50), (3, 'Phil''s Business', '789 Avenue', 50);
不同数据库的写法:
- MySQL/MariaDB 使用
GROUP_CONCAT:
SELECT order_id, GROUP_CONCAT(order_contact SEPARATOR ', ') AS combined_contacts, order_location, order_value FROM orders GROUP BY order_id, order_location, order_value;
- PostgreSQL 使用
STRING_AGG:
SELECT order_id, STRING_AGG(order_contact, ', ') AS combined_contacts, order_location, order_value FROM orders GROUP BY order_id, order_location, order_value;
- SQL Server 2017+ 也支持
STRING_AGG:
SELECT order_id, STRING_AGG(order_contact, ', ') AS combined_contacts, order_location, order_value FROM orders GROUP BY order_id, order_location, order_value;
- SQL Server 2016及更早版本 可以用
STUFF+FOR XML PATH的组合:
SELECT o.order_id, STUFF((SELECT ', ' + order_contact FROM orders WHERE order_id = o.order_id FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'), 1, 2, '') AS combined_contacts, o.order_location, o.order_value FROM orders o GROUP BY o.order_id, o.order_location, o.order_value;
执行后你会得到这样的结果:
| order_id | combined_contacts | order_location | order_value |
|---|---|---|---|
| 1 | Tom's Business, John's Management | 123 Street | 100 |
| 2 | Tim's Business | 543 Avenue | 50 |
| 3 | Phil's Business | 789 Avenue | 50 |
方法二:自JOIN(仅适合同order_id最多两条记录的场景)
如果你的数据里每个order_id最多只有两条不同的order_contact,可以用自JOIN来合并,但这个方法局限性很大,不推荐用于通用场景:
-- 合并order_id=1的两条记录 SELECT o1.order_id, CONCAT(o1.order_contact, ', ', o2.order_contact) AS combined_contacts, o1.order_location, o1.order_value FROM orders o1 JOIN orders o2 ON o1.order_id = o2.order_id AND o1.order_contact < o2.order_contact WHERE o1.order_id = 1 -- 再把其他单独的记录加进来 UNION ALL SELECT order_id, order_contact AS combined_contacts, order_location, order_value FROM orders WHERE order_id NOT IN (1);
这个方法如果遇到同一个order_id有3条及以上记录,会生成重复的组合结果,所以还是方法一更靠谱。
再啰嗦下UNION的正确用法
你之前以为UNION适用于不同结构的数据集,刚好相反:UNION要求两个查询结果的列数、列数据类型必须完全匹配,它的作用是把两个结果集上下拼接起来。比如你有两个订单表orders_2023和orders_2024,结构完全一样,要合并成一个全年的订单列表,就可以用:
SELECT * FROM orders_2023 UNION ALL SELECT * FROM orders_2024;
用UNION会自动去重(如果有重复的订单记录),UNION ALL则保留所有记录,效率更高。
内容的提问来源于stack exchange,提问作者sergio089
相关产品推荐
相关产品推荐

