STRING_SPLIT函数需SQL Server 2016+且兼容级别≥130,仅支持单字符分隔符,返回无序value列;NULL输入返回空结果集,连续分隔符产生空项,首尾空格不自动TRIM;2022+可用ordinal参数保序,此前须手动ROW_NUMBER()或改用DelimitedSplit8K等替代方案。

STRING_SPLIT 函数的基本用法和必要前提
SQL Server 2016+ 才支持 STRING_SPLIT,低版本(如 2014 或更早)直接调用会报错:Invalid object name 'STRING_SPLIT'。它只能拆分单个字符串,返回一个含 value 列的表,不保证顺序——这点极易被忽略,后续做位置关联时可能出错。
- 必须启用兼容级别 130 或更高(对应 SQL Server 2016)
- 输入字符串不能为
NULL,否则返回空结果集(不是一行NULL) - 分隔符只能是单字符,
','可以,',' + CHAR(32)(带空格)需先清理
SELECT value FROM STRING_SPLIT('a,b,c', ',');结果三行:a、b、c,但顺序不保证,尤其在 JOIN 或子查询中依赖序号时要格外小心。
如何保留原始顺序并编号
STRING_SPLIT 不返回序号,但 SQL Server 2022+ 支持带 ordinal 参数的重载版本:STRING_SPLIT('a,b,c', ',', 1),此时返回 value 和 ordinal 两列,ordinal 从 1 开始。
- 2022 之前版本必须手动加序号,常用方式是用
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)),但注意:这不能保证与原字符串中位置一致(因无稳定排序依据) - 更可靠的做法是先用
CHARINDEX+SUBSTRING拆解(复杂),或改用数字辅助表 +DelimitedSplit8K等社区函数
-- SQL Server 2022+
SELECT value, ordinal FROM STRING_SPLIT('x,y,z', ',', 1);处理空值、空字符串和连续分隔符
STRING_SPLIT 对 'a,,b' 会返回三行:'a'、''(空字符串)、'b';对 ' , b ' 会原样保留首尾空格,不会自动 TRIM。
- 连续逗号产生空字符串行,常需过滤:
WHERE NULLIF(value, '') IS NOT NULL - 首尾空格需显式处理:
TRIM(value)(SQL Server 2017+)或RTRIM(LTRIM(value)) - 若源字段可能为
NULL,应在外层加CROSS APPLY并用ISNULL或COALESCE防止整个结果丢失
SELECT TRIM(s.value) AS item FROM dbo.MyTable t CROSS APPLY STRING_SPLIT(ISNULL(t.tag_list, ''), ',') s WHERE NULLIF(TRIM(s.value), '') IS NOT NULL;
替代方案:为什么有时不该用 STRING_SPLIT
STRING_SPLIT 是表值函数,不可内联展开,执行计划里常表现为“远程查询”或额外嵌套,大数据量下性能不如静态拆分逻辑。另外它不支持多字符分隔符,也不支持正则。
- 需要稳定顺序且非 2022+:优先考虑
DelimitedSplit8K_LEAD(Jeff Moden 版本,性能极佳) - 要匹配模式(如跳过引号内逗号):必须用 CLR 或外部 ETL 处理
- 在视图或内联表值函数中使用时,可能因无法参数化而影响可重用性
真正麻烦的不是“怎么拆”,而是“拆完怎么安全地 join 回原记录”——尤其是当原字段含重复值、空值、超长字符串时,CROSS APPLY 的语义边界很容易被误读。

















