SQL中如何将同ID多行数据合并为单行?附需求示例
合并同OrderID记录的SQL解决方案
嘿,我来帮你搞定这个需求!你需要把同一个OrderID对应的多条记录合并成单行,提取各支付字段的非空值,同时把ReciptNo用逗号拼接起来。下面分不同数据库给出具体的实现代码,还有思路说明:
核心逻辑拆解
- 支付字段(Cash、Nets、Visa等):同一个OrderID下每个支付字段应该只有一个有效非空值(从你的示例来看是这样),所以用
MAX()或者MIN()聚合函数就能轻松提取——因为这些函数会自动忽略NULL值,只保留唯一的有效值。 - ReciptNo拼接:不同数据库有各自的字符串聚合函数,用来把多个ReciptNo值用逗号连起来。
- 其他字段(OrderDate、ItemNo等):假设同一个OrderID下这些字段的值是一致的,同样用
MAX()/MIN()就能拿到唯一值,如果实际有不同值,你可以根据业务需求调整聚合方式。
1. MySQL/MariaDB版本
SELECT MAX(OrderDate) AS OrderDate, OrderID, MAX(ItemNo) AS ItemNo, MAX(PaymentType) AS PaymentType, MAX(Cash) AS Cash, MAX(Nets) AS Nets, MAX(Visa) AS Visa, MAX(AMEX) AS AMEX, MAX(MasterCard) AS MasterCard, MAX(Voucher) AS Voucher, MAX(Remarks) AS Remarks, GROUP_CONCAT(ReciptNo SEPARATOR ',') AS ReciptNo FROM your_table_name -- 替换成你的实际表名 GROUP BY OrderID;
小提示:如果ReciptNo有重复值,想去掉重复的话,加个
DISTINCT就行:GROUP_CONCAT(DISTINCT ReciptNo SEPARATOR ',')
2. SQL Server 2017+/Azure SQL版本
SELECT MAX(OrderDate) AS OrderDate, OrderID, MAX(ItemNo) AS ItemNo, MAX(PaymentType) AS PaymentType, MAX(Cash) AS Cash, MAX(Nets) AS Nets, MAX(Visa) AS Visa, MAX(AMEX) AS AMEX, MAX(MasterCard) AS MasterCard, MAX(Voucher) AS Voucher, MAX(Remarks) AS Remarks, STRING_AGG(ReciptNo, ',') AS ReciptNo FROM your_table_name -- 替换成你的实际表名 GROUP BY OrderID;
小提示:SQL Server 2022及以上版本支持去重,写法是
STRING_AGG(DISTINCT ReciptNo, ',')
3. Oracle 11g+版本
SELECT MAX(OrderDate) AS OrderDate, OrderID, MAX(ItemNo) AS ItemNo, MAX(PaymentType) AS PaymentType, MAX(Cash) AS Cash, MAX(Nets) AS Nets, MAX(Visa) AS Visa, MAX(AMEX) AS AMEX, MAX(MasterCard) AS MasterCard, MAX(Voucher) AS Voucher, MAX(Remarks) AS Remarks, LISTAGG(ReciptNo, ',') WITHIN GROUP (ORDER BY ReciptNo) AS ReciptNo FROM your_table_name -- 替换成你的实际表名 GROUP BY OrderID;
小提示:Oracle 19c及以上支持去重,写法是
LISTAGG(DISTINCT ReciptNo, ',') WITHIN GROUP (ORDER BY ReciptNo);低版本需要先子查询去重再聚合。
4. PostgreSQL版本
SELECT MAX(OrderDate) AS OrderDate, OrderID, MAX(ItemNo) AS ItemNo, MAX(PaymentType) AS PaymentType, MAX(Cash) AS Cash, MAX(Nets) AS Nets, MAX(Visa) AS Visa, MAX(AMEX) AS AMEX, MAX(MasterCard) AS MasterCard, MAX(Voucher) AS Voucher, MAX(Remarks) AS Remarks, STRING_AGG(ReciptNo, ',' ORDER BY ReciptNo) AS ReciptNo FROM your_table_name -- 替换成你的实际表名 GROUP BY OrderID;
小提示:去重的话直接加
DISTINCT:STRING_AGG(DISTINCT ReciptNo, ',' ORDER BY ReciptNo)
额外注意点
- 一定要把代码里的
your_table_name替换成你实际使用的数据表名称哦。 - 如果同一个OrderID下的
OrderDate、ItemNo等字段存在不同值,你得根据业务逻辑调整聚合方式——比如取最新的OrderDate,或者指定某个ItemNo。 - 如果某个支付字段在同一个OrderID下有多条非空记录(比如两行都有Cash值),
MAX()会取最大值,要是你需要求和的话,把MAX()换成SUM()就可以了。
内容的提问来源于stack exchange,提问作者Tushar
相关产品推荐
相关产品推荐

