优先用STRING_AGG(2017+),必须带WITHIN GROUP排序、显式处理NULL(如ISNULL)、去重需前置子查询或CTE,空组返回NULL需COALESCE兜底,不可嵌套聚合或误用外部ORDER BY。

SQL Server 存储过程中合并多行文本,优先用 STRING_AGG(2017+),别硬套 FOR XML PATH 或游标——后者易出错、难维护、性能差。
STRING_AGG 必须带 WITHIN GROUP 排序
STRING_AGG 在存储过程里不写 WITHIN GROUP 就会报错或结果乱序,外部 ORDER BY 完全无效。
- 错误写法:
STRING_AGG(name, ', ')→ SQL Server 直接报错:“The string_agg function requires an ORDER BY clause.” - 正确写法:
STRING_AGG(name, ', ') WITHIN GROUP (ORDER BY id) - 若想按原始插入顺序排,而表又没可靠排序字段,得提前加
ROW_NUMBER()临时列,再在WITHIN GROUP里引用它
NULL 值会让整行从聚合中消失
STRING_AGG 默认跳过 NULL 值,不是留空,是彻底剔除该行。如果某条记录的 name 是 NULL,它不会变成 ',' 中的空位,而是直接被忽略。
- 显式兜底:
STRING_AGG(ISNULL(name, '(null)'), ', ')或STRING_AGG(COALESCE(name, ''), ', ') - 注意:
SEPARATOR不能为 NULL;SQL Server 2017 不支持SEPARATOR ''语法,要写成STRING_AGG(name, '') - 空字符串分隔符在某些场景下会导致结果粘连(如
'a' + '' + 'b'→'ab'),务必确认业务是否允许
去重和分组逻辑必须前置处理
STRING_AGG 本身不支持 DISTINCT,也不能在函数内部去重。想合并前去重,得把去重逻辑放在子查询或 CTE 里。
- 错误尝试:
STRING_AGG(DISTINCT name, ', ')→ 语法错误 - 可行做法:
SELECT STRING_AGG(name, ', ') FROM (SELECT DISTINCT name FROM @temp_table) t - 如果合并依据是某个外键(如
order_id),且需保留所有主表记录(包括无明细的),不能只靠GROUP BY,得用LEFT JOIN+ 聚合子查询,否则空组直接消失
别在存储过程里对 STRING_SPLIT 结果开游标
拆分后想逐行处理?常见反模式是用游标遍历 STRING_SPLIT 返回值——慢、锁多、难以调试。
-
STRING_SPLIT返回单列结果集(value),不能用于INSERT ... VALUES (...),否则报“子查询返回多行” - 正确插入方式:
INSERT INTO target(col) SELECT value FROM STRING_SPLIT(@input, ',') - 需要编号或顺序?SQL Server 2017 没
ordinal列,得自己加:SELECT value, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS rn FROM STRING_SPLIT(@s, ',')
最易被忽略的是:聚合结果为空时返回 NULL 而非空字符串,后续逻辑若没用 COALESCE(..., '') 包一层,下游应用可能崩掉或显示异常。别等上线后才发现字段突然变 NULL。

















