合法,STRING_AGG(DISTINCT col, ',')是SQL Server 2017+官方支持语法,DISTINCT须紧贴函数名后、参数前;必须配合WITHIN GROUP排序,NULL默认跳过,空字符串参与去重,去重性能受索引影响。

STRING_AGG(DISTINCT ...) 语法是否合法?
合法,但仅限 SQL Server 2017 及以上版本(含 2019)。STRING_AGG 支持在第一个参数前直接写 DISTINCT,这是官方语法,不是 hack。错误写法如 STRING_AGG(DISTINCT(col), ',') 或 STRING_AGG(DISTINCT col ORDER BY ...)(ORDER BY 必须放在 WITHIN GROUP 中)会报错。
去重时 NULL 和空字符串怎么处理?
STRING_AGG 默认跳过 NULL 值,但不会跳过空字符串 ''。如果原始数据含大量 '',它们会被当作有效值参与去重和拼接,导致结果里出现冗余逗号或意外长度。
- 过滤空值:
WHERE column_name IS NOT NULL AND column_name != '' - 把
NULL当普通值处理:用COALESCE(column_name, 'NULL')替换 - 统一大小写去重:
STRING_AGG(DISTINCT LOWER(column_name), ', ')
排序必须用 WITHIN GROUP,不能靠外部 ORDER BY
想让拼接结果按字母序或时间序排列,必须用 WITHIN GROUP (ORDER BY ...),且它只能跟在 STRING_AGG 的括号后、分号前。外部的 ORDER BY 不影响拼接内容顺序。
- 正确:
STRING_AGG(DISTINCT value, ', ') WITHIN GROUP (ORDER BY value) - 错误:
STRING_AGG(DISTINCT value, ', ') ORDER BY value(语法错误) - 注意:
WITHIN GROUP中的排序字段类型需与去重字段一致,否则可能隐式转换失败
性能敏感时要注意索引和数据量
DISTINCT 在聚合内部触发哈希去重,大数据量下可能明显拖慢查询。尤其当目标列未建索引、或重复率很低时,开销更显著。
- 建议在被聚合的列上建非聚集索引,例如:
CREATE NONCLUSTERED INDEX IX_sample_value ON sampledata(value) - 若只是临时去重拼接,且数据量超百万行,先用 CTE 或子查询
SELECT DISTINCT预处理,再喂给STRING_AGG,有时比单条语句更可控 -
WITHIN GROUP加了ORDER BY后,SQL Server 可能执行两次排序(去重 + 排序),实测在 2019 CU 版本中仍存在该行为

















