string_split在sql server 2016+中拆分逗号字符串时不保证顺序、忽略空元素且不兼容旧版本;需用row_number()或2022+的ordinal参数保序,预处理保留空值,旧版改用xml/openjson,join时注意性能。

STRING_SPLIT 在 SQL Server 2016+ 中能直接拆分逗号字符串,但默认不保证顺序、不处理空元素、不能跨版本使用——别直接套用示例就跑,先看这几个关键点。
STRING_SPLIT 返回结果无序,需要显式排序
函数返回的是表值结果集,STRING_SPLIT 不提供原始位置信息。如果原字符串是 'apple,banana,cherry',查询结果可能乱序,尤其在 JOIN 或子查询中容易出错。
正确做法是用 ROW_NUMBER() 配合 ORDER BY (SELECT NULL)(SQL Server 2022+ 支持 ordinal 参数):
SELECT value, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS pos
FROM STRING_SPLIT('a,b,c', ',');
注意:ORDER BY (SELECT NULL) 是兼容写法,仅表示“按输入顺序”,但 SQL Server 不保证物理顺序;真正可靠的方式是升级到 2022 并启用 ordinal:
SELECT value, ordinal
FROM STRING_SPLIT('a,b,c', ',', 1); -- 第三个参数 1 表示启用 ordinal
空字符串和连续逗号会被忽略
输入 'a,,b' 时,STRING_SPLIT 默认只返回两行:'a' 和 'b',中间的空值被丢弃。这不是 bug,是设计行为。
若业务要求保留空项(比如 CSV 解析),必须预处理字符串:
- 把
','替换为', '(加空格)再 trim?不可靠,会污染数据 - 更稳妥:用
REPLACE把空位转成占位符,如REPLACE('a,,b', ',,', ',[NULL],'),再拆分后替换回NULL - 或者改用自定义拆分函数(如用
WHILE+CHARINDEX),控制空值逻辑
不能在旧版本 SQL Server 中使用
STRING_SPLIT 是 SQL Server 2016 引入的,2014 及更早版本直接执行会报错:Invalid object name 'STRING_SPLIT'。
替代方案只有两个:
- 创建兼容函数(如用
XML+nodes()拆分,但要注意特殊字符需转义) - 用
OPENJSON(SQL Server 2016+ 也支持,但要求输入是 JSON 数组格式,得先包装成'["a","b","c"]')
如果无法升级又必须用原生方式,XML 方案最常用,但遇到 &、、<code>> 会解析失败,务必先 REPLACE 转义。
JOIN 使用时性能可能意外下降
在大表上 CROSS APPLY STRING_SPLIT(...) 容易触发嵌套循环,尤其当拆分字段含长字符串或大量逗号时,执行计划可能退化。
优化建议:
- 确保被拆分的列上有索引(虽然
STRING_SPLIT本身不走索引,但外层过滤可受益) - 避免在 WHERE 条件里对
STRING_SPLIT结果做函数操作,例如WHERE UPPER(value) = 'A'会阻止内联优化 - 拆分后立即用
WHERE value != ''过滤(即使你认为没空值,也加上——防止隐式转换开销)
真正麻烦的不是语法,而是空值语义和顺序依赖。用之前先确认你的数据里有没有 ,,、开头结尾逗号、Unicode 逗号(如全角,,),这些都不会被 STRING_SPLIT 识别。










