只有SQL Server 2017及更高版本(含Azure SQL Database)原生支持STRING_AGG;低版本会报错“Invalid object name 'STRING_AGG'”,须改用FOR XML PATH('')等替代方案,且必须配合GROUP BY使用,并通过WITHIN GROUP (ORDER BY ...)显式指定排序以保证结果稳定。

STRING_AGG 在 SQL Server 2017+ 中是否可用?
只有 SQL Server 2017 及更高版本(含 Azure SQL Database)原生支持 STRING_AGG。SQL Server 2016 或更早版本直接执行会报错:Invalid object name 'STRING_AGG'。若无法升级,需改用 FOR XML PATH('') 或 CLR 聚合函数替代。
STRING_AGG 基本语法和排序控制
STRING_AGG 默认不保证顺序,必须显式用 WITHIN GROUP (ORDER BY ...) 指定排序逻辑,否则每次执行结果可能不同。
- 正确写法:
STRING_AGG(column_name, ',') WITHIN GROUP (ORDER BY id) - 错误写法:
STRING_AGG(column_name, ',') ORDER BY id(语法错误) - 分隔符可以是任意字符串,包括空格、换行符(
CHAR(10))、制表符(CHAR(9)),但不能为NULL;传入NULL分隔符会导致整个表达式返回NULL - 被拼接字段值为
NULL时自动跳过,不会插入空项或额外分隔符
在 GROUP BY 查询中使用 STRING_AGG 的典型场景
常见于将一对多关系“压平”展示,例如一个部门下多个员工姓名合并成单个字段。
SELECT dept_id, STRING_AGG(emp_name, '; ') WITHIN GROUP (ORDER BY emp_name) AS emp_list FROM employees GROUP BY dept_id;
- 若需去重后再拼接,
STRING_AGG本身不支持DISTINCT,须先用子查询或 CTE 去重:SELECT dept_id, STRING_AGG(emp_name, ', ') WITHIN GROUP (ORDER BY emp_name) FROM (SELECT DISTINCT dept_id, emp_name FROM employees) t GROUP BY dept_id - 拼接结果长度上限为
varchar(max)(2GB),但实际受内存与查询超时限制;若数据量极大,建议加WHERE过滤或分页聚合 - 与
GROUP BY配合时,所有非聚合字段都必须出现在GROUP BY列表中,否则报错:Column 'xxx' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause
STRING_AGG 和旧方案 FOR XML PATH 对比要注意什么?
FOR XML PATH('') 方案虽兼容老版本,但存在隐式类型转换风险和可读性差的问题。
-
STRING_AGG返回类型是varchar(max)(或nvarchar(max),取决于输入),而FOR XML默认返回xml类型,需额外.value('.', 'NVARCHAR(MAX)')转换 -
FOR XML会自动对特殊字符(如&、)做 HTML 实体编码,而STRING_AGG原样拼接,无转义行为 -
STRING_AGG不支持嵌套聚合,例如不能在STRING_AGG内部再套一层聚合函数;而FOR XML可通过子查询绕过该限制(但更难维护)
真正容易被忽略的是:当拼接字段含换行或不可见字符时,STRING_AGG 会如实保留,导出到 Excel 或日志里可能造成格式错乱,建议提前用 REPLACE 或 TRIM 清洗。










