STRING_AGG是SQL Server 2017+引入的原生聚合函数,用于将多行字符串按指定分隔符拼接成一行,支持WITHIN GROUP(ORDER BY...)排序,空值默认跳过,低版本需用FOR XML PATH('')等方案替代。

SQL Server 2017+ 直接用 STRING_AGG,低版本必须绕路
STRING_AGG 是 SQL Server 2017 引入的原生聚合函数,解决多行变一行最直接的方式。如果你用的是 2016 或更早版本,它根本不存在——调用会报错 Invalid object name 'STRING_AGG',别试了,得换方案。
实操建议:
- 先查版本:
SELECT @@VERSION,确认是否 ≥ 2017(含 Express、Standard、Enterprise) - 注意:Azure SQL Database 默认支持,但某些旧版托管实例可能未启用,需检查兼容级别 ≥ 140
- 语法结构固定:
STRING_AGG(<expression>, <>separator>) [WITHIN GROUP (ORDER BY ...)],ORDER BY必须写在WITHIN GROUP里,不能放外面
STRING_AGG 的分隔符和排序必须显式声明,空值默认被跳过
很多人以为不写 ORDER BY 就按表顺序拼,实际结果是未定义的——SQL Server 不保证无序聚合的输出顺序。同样,NULL 值不会变成 'NULL' 字符串,而是直接忽略,整段里“消失”。
实操建议:
- 强制排序:哪怕只是按主键排,也加上
WITHIN GROUP (ORDER BY id) - 处理空值:如果字段可能为
NULL,用ISNULL(col, '')或COALESCE(col, '')转成空字符串再拼 - 分隔符要加引号:写
',',别写,(后者是语法错误) - 示例:
STRING_AGG(ISNULL(name, ''), '; ') WITHIN GROUP (ORDER BY sort_order)
SQL Server 2016 及更早:用 FOR XML PATH('') 模拟,但得防特殊字符转义
经典替代方案是 SELECT STUFF((SELECT ',' + col FROM t FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')。它本质是把子查询结果拼成 XML 片段再取文本,但 &、、<code>> 会被自动转义成 &、<、>,导致数据失真。
实操建议:
- 加
TYPE关键字后用.value('.', 'NVARCHAR(MAX)')才能正确解码 XML 实体 - 避免用
CAST(... AS XML)简写,它不处理转义,风险更高 - 开头用
STUFF去掉首个多余分隔符,比SUBSTRING更安全(空结果不报错) - 性能上,大数据量时
FOR XML比STRING_AGG慢 20%–40%,且无法并行优化
GROUP BY 和 NULL 处理容易漏掉,尤其跨表 JOIN 后
合并常用于关联查询后对子集汇总,比如“每个订单的所有商品名拼成一行”。这时若 LEFT JOIN 导致某订单没有商品,STRING_AGG 返回 NULL,而 FOR XML 方案返回空字符串——行为不一致,业务逻辑可能出错。
实操建议:
- 确认
GROUP BY列完整覆盖所有非聚合字段,否则报错Column is invalid in the select list - JOIN 后聚合前,用
ISNULL(STRING_AGG(...), '(none)')显式控制空值表现 - 测试边界:空子集、单行、含重复值、含换行符的字段(
STRING_AGG保留换行,FOR XML会转成)

















