STRING_AGG适用于SQL Server 2017+及Azure SQL(兼容级≥140),须配合GROUP BY与WITHIN GROUP排序,支持DISTINCT和ISNULL处理NULL;低版本需用FOR XML PATH('') + STUFF,注意转义、空值和性能差异。

直接用 STRING_AGG,但前提是 SQL Server 版本 ≥ 2017(含 Azure SQL Database);低于该版本调用会报错 Invalid object name 'STRING_AGG',没得商量。
确认你的 SQL Server 是否支持 STRING_AGG
别猜,先查版本:
- 运行
SELECT @@VERSION;—— 输出里必须含2017、2019、2022或Azure SQL Database - Azure SQL 托管实例要注意兼容级别:执行
SELECT DATABASEPROPERTYEX(DB_NAME(), 'CompatibilityLevel');,结果需 ≥140 - SQL Server 2016 及更早?放弃
STRING_AGG,改用FOR XML PATH('')+STUFF组合
STRING_AGG 必须配合 GROUP BY,且排序不能省
它不是标量函数,不能裸用。常见错误是写成:
SELECT STRING_AGG(name, ', ') FROM users; → 报错:STRING_AGG is not allowed in the context
正确姿势:
- 明确分组维度:
SELECT dept_id, STRING_AGG(name, '; ') FROM users GROUP BY dept_id; - 顺序不加
WITHIN GROUP就是未定义行为——哪怕表有聚集索引,结果也可能每次不同 -
WITHIN GROUP (ORDER BY ...)是独立子句,必须写在STRING_AGG(...)括号外,不能塞进括号里 - 排序字段必须属于
GROUP BY列,或为聚合表达式(如MIN(hire_date)),不能引用未分组的别名
空值、分隔符和去重的实际处理
STRING_AGG 默认跳过 NULL,但业务常需要“占位”或“显式留空”:
- 把
NULL转成空字符串:STRING_AGG(ISNULL(email, ''), ', ') - 分隔符必须是字符串字面量或变量,
','对,,错(后者语法报错) - 去重不用绕路:直接在
STRING_AGG内加DISTINCT,例如STRING_AGG(DISTINCT tag, ', ') - 想用换行符分隔?写
CHAR(10),但 SSMS 网格视图默认不渲染,右键结果 → “在文本中显示结果”才看得见
低版本替代方案:FOR XML PATH('') 的坑比想象中多
SQL Server 2016 及以前只能靠这个“古法”拼接,但细节极易出错:
- 必须加
TYPE和.value('.', 'NVARCHAR(MAX)'),否则&、、>会被转义成&、、> - 开头用
STUFF(..., 1, 1, '')去掉首分隔符,比SUBSTRING更安全(空结果不报错) - LEFT JOIN 后若子集为空,
FOR XML返回空字符串,而STRING_AGG返回NULL——行为不一致,容易漏掉空分组逻辑 - 大数据量时性能差 20%–40%,且无法并行执行
最易被忽略的一点:无论用哪个方案,只要涉及跨表 JOIN 后聚合,都得提前想清楚 NULL 是该跳过、转空串,还是体现为占位符——这直接影响报表语义,但往往到上线才发现对不上数。










