如何将SQL Server中同一账号(PK)的多行交易数据合并为单行?
嘿,这个场景我经常碰到!在SQL Server里,把同一账号的多行交易数据合并到一行,主要有两种常用方案,看你用的是哪个版本的SQL Server:
方案1:使用
STRING_AGG(SQL Server 2017+ 推荐) 这个函数是SQL Server 2017及以后版本引入的,专门用来聚合字符串,语法简洁到爆。你可以按账号分组,然后把交易值和交易日期分别(或者一起)拼接成字符串:
示例代码:
SELECT Acc#, -- 拼接交易值,按交易日期倒序排列 STRING_AGG(TransactionValue, ', ') WITHIN GROUP (ORDER BY TransactionDate DESC) AS CombinedTransactionValues, -- 拼接交易日期,同样按日期排序 STRING_AGG(CONVERT(VARCHAR, TransactionDate, 105), ', ') WITHIN GROUP (ORDER BY TransactionDate DESC) AS CombinedTransactionDates, -- 也可以把值和日期配对拼接,比如 "R2500 (25-04-2018), R5235 (23-04-2018)" STRING_AGG(CONCAT(TransactionValue, ' (', CONVERT(VARCHAR, TransactionDate, 105), ')'), ', ') WITHIN GROUP (ORDER BY TransactionDate DESC) AS CombinedTransactions FROM YourTableName GROUP BY Acc#;
解释一下:
STRING_AGG(要聚合的字段, 分隔符)会把同一组的字段值用分隔符连起来WITHIN GROUP (ORDER BY ...)可以指定拼接的顺序,比如按交易日期从新到旧排CONVERT(VARCHAR, TransactionDate, 105)是把日期转成dd-mm-yyyy的格式,和你示例里的一致
运行你给的示例数据,结果会是:
Acc# CombinedTransactionValues CombinedTransactionDates CombinedTransactions ---------- ------------------------- ------------------------- ------------------------------- 123658421 R2500, R5235 25-04-2018, 23-04-2018 R2500 (25-04-2018), R5235 (23-04-2018)
方案2:使用
FOR XML PATH(兼容SQL Server 2016及更早版本) 如果你的SQL Server版本比较旧,没法用STRING_AGG,那就用这个经典的XML拼接方法:
示例代码:
SELECT DISTINCT Acc#, -- 拼接交易值 STUFF(( SELECT ', ' + TransactionValue FROM YourTableName t2 WHERE t2.Acc# = t1.Acc# ORDER BY t2.TransactionDate DESC FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)'), 1, 2, '') AS CombinedTransactionValues, -- 拼接交易日期 STUFF(( SELECT ', ' + CONVERT(VARCHAR, TransactionDate, 105) FROM YourTableName t2 WHERE t2.Acc# = t1.Acc# ORDER BY t2.TransactionDate DESC FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)'), 1, 2, '') AS CombinedTransactionDates, -- 配对拼接值和日期 STUFF(( SELECT ', ' + CONCAT(TransactionValue, ' (', CONVERT(VARCHAR, TransactionDate, 105), ')') FROM YourTableName t2 WHERE t2.Acc# = t1.Acc# ORDER BY t2.TransactionDate DESC FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)'), 1, 2, '') AS CombinedTransactions FROM YourTableName t1;
解释一下:
- 子查询里用
FOR XML PATH('')会把查询结果拼成一个XML字符串(没有标签) TYPE参数确保特殊字符被正确处理(比如如果交易值里有&、<这些符号不会乱码)STUFF(..., 1, 2, '')是去掉字符串开头的,(因为子查询开头会多一个分隔符)
这个方法的结果和方案1完全一样,只是写法繁琐一点,但胜在兼容性好。
额外说明
如果你不是要把多个值拼成字符串,而是要把不同日期的交易值拆成单独的列(比如第一笔交易、第二笔交易各占一列),那你需要用PIVOT或者动态SQL来实现,但从你的描述来看,应该是要合并成同一行的字符串列,上面两种方法就足够了。
记得把代码里的YourTableName换成你实际的表名哦!
内容的提问来源于stack exchange,提问作者Z.L
相关产品推荐
相关产品推荐

