STRING_AGG仅SQL Server 2017+原生支持,须配合GROUP BY使用,分隔符必须为字符串常量且不可省略,排序需用WITHIN GROUP(ORDER BY...),默认跳过NULL值。

STRING_AGG在SQL Server 2017+中是否可用
只有 SQL Server 2017(14.x)及更高版本才原生支持 STRING_AGG。如果你用的是 2016 或更早版本,直接调用会报错:Invalid column name 'STRING_AGG' 或 Incorrect syntax near 'STRING_AGG'。别折腾兼容写法——老版本请改用 FOR XML PATH('') 或 CLR 函数,STRING_AGG 不是“可选功能”,是版本硬门槛。
基本语法和分隔符控制
STRING_AGG 必须配合 GROUP BY 使用,它不是标量函数,不能单独对单行求值。最简形式是 STRING_AGG(<expression>, <separator>),第二个参数是字符串字面量,**必须加单引号**,哪怕只想要空字符串分隔('')也不能省略。
常见误写:
- 漏掉分隔符参数 → 报错
Incorrect syntax near ',' - 用变量或列名当分隔符(如
STRING_AGG(name, sep_col))→ 不支持,只能是常量 - 分隔符含换行或制表符 → 虽然语法允许(如
'<br>'
),但结果可能被客户端截断或显示异常,建议先用REPLACE清理源数据
示例:把每个部门的员工姓名用顿号拼接
SELECT dept, STRING_AGG(name, '、') AS names FROM employees GROUP BY dept;
排序影响结果顺序,且必须在WITHIN GROUP中声明
STRING_AGG 默认不保证拼接顺序。想让“张三、李四、王五”稳定出现,必须显式加 WITHIN GROUP (ORDER BY ...)。这个子句**必须紧贴在括号后、分号前**,不能放到 GROUP BY 后面,也不能用窗口函数语法。
容易踩的坑:
- 写成
STRING_AGG(name, ',') ORDER BY name→ 语法错误,ORDER BY不属于聚合函数上下文 - 在
WITHIN GROUP里引用别名(如WITHIN GROUP (ORDER BY names))→ 别名尚未生成,报错Invalid column name - 排序字段含 NULL → 默认排在最前,若要 NULL 排最后,得写
ORDER BY sort_col DESC NULLS LAST(注意:SQL Server 目前不支持NULLS LAST语法,需用ORDER BY CASE WHEN sort_col IS NULL THEN 1 ELSE 0 END, sort_col曲线救国)
正确写法:
SELECT dept, STRING_AGG(name, ',') WITHIN GROUP (ORDER BY hire_date DESC) AS names_by_hire FROM employees GROUP BY dept;
处理NULL值和空字符串的边界情况
STRING_AGG 默认**跳过 NULL 值**,这点和 CONCAT 不同。如果某组所有值都是 NULL,结果返回 NULL;如果混有 NULL 和非 NULL,则 NULL 被忽略,只拼非 NULL 部分。
但要注意:空字符串 '' 不等于 NULL,它会被当作有效值参与拼接。例如 STRING_AGG('', ',') 会产出 ','(两个逗号间夹着空串)。
实用建议:
- 想把 NULL 当成 '未知' 处理?先用
ISNULL(name, '<未知>')或COALESCE(name, '<未知>')转换 - 想过滤掉空字符串再拼?加
WHERE name != ''或在表达式里套NULLIF(name, '')(这样空串变 NULL,就被自动跳过了) - 拼接结果超长被截断?
STRING_AGG返回varchar(max),但若中间某字段是text或ntext类型,可能触发隐式转换失败,建议统一转为varchar(max)或nvarchar(max)
实际中,最常被忽略的是排序 + NULL 处理的组合:既要按时间倒序,又要把 NULL 入职日期的人排到最后——这需要嵌套 CASE,不是加个 WITHIN GROUP 就能搞定的。

















