SQL Server 2017+ 必须用 STRING_AGG 合并多行字符串,且必须指定 WITHIN GROUP(ORDER BY ...),否则报错;NULL 被跳过,空组返回 NULL,不支持 DISTINCT 和嵌套聚合,去重与保序需前置处理。

SQL Server 2017+ 存储过程中合并多行字符串,必须用 STRING_AGG,不能靠变量累加或 FOR XML PATH —— 后者在复杂逻辑里容易出错,且无法保证排序稳定性。
STRING_AGG 必须带 WITHIN GROUP(ORDER BY ...)
STRING_AGG 在存储过程里不写 WITHIN GROUP 就会直接报错:“The string_agg function requires an ORDER BY clause.” 外部的 ORDER BY 对聚合结果完全无效。
- 正确写法:
STRING_AGG(name, ', ') WITHIN GROUP (ORDER BY id) - 若原始顺序不可靠(比如没主键/时间戳),得先加序号:
SELECT name, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS rn FROM @t,再在WITHIN GROUP里按rn排 - 分隔符为空字符串时写成
STRING_AGG(name, ''),SQL Server 2017 不支持SEPARATOR ''语法
NULL 值默认被跳过,不是留空
STRING_AGG 遇到 NULL 字段值,整行记录直接从聚合中剔除,不会生成逗号占位。如果业务要求显示 (null) 或空字符串,必须提前转换。
- 显式兜底:
STRING_AGG(ISNULL(name, '(null)'), ', ')或STRING_AGG(COALESCE(name, ''), ', ') - 注意:
COALESCE和ISNULL返回类型需与字段一致,否则可能截断;ISNULL更快但只支持两个参数 - 聚合结果本身为空组时返回
NULL,后续逻辑若拼接失败,得用COALESCE(..., '')包一层
去重和空组保留得靠子查询或 CTE
STRING_AGG 本身不支持 DISTINCT,也不能在函数内部写去重逻辑。想合并前去重,或者保留无明细的主表记录,必须把处理逻辑前置。
- 去重:用子查询包裹
SELECT DISTINCT name FROM @temp,再对结果集调用STRING_AGG - 空组保留(如 LEFT JOIN 后某 order_id 没明细):不能只靠
GROUP BY,得把聚合逻辑封装进子查询或 CTE,再和主表关联 - 禁止嵌套聚合:比如
STRING_AGG(MAX(col), ', ')会报错,聚合函数不能出现在STRING_AGG参数中
最易被忽略的是:空结果组返回 NULL,而不是空字符串;还有 STRING_SPLIT 返回的顺序不可靠,别指望它和输入字符串字符位置一致——2017 版本没有 ordinal 列,硬要保序就得自己加 ROW_NUMBER()。










