string_split在sql server 2022中必须传第三个参数1才能返回ordinal列,否则仅返回value列且顺序不可靠;ordinal从1开始按子串出现顺序编号,不支持自动排序或优化器下推。

STRING_SPLIT在SQL Server 2022中必须传第三个参数才返回ordinal列
不加第三个参数,STRING_SPLIT 返回的永远只有 value 一列,且顺序完全不可靠——哪怕你反复执行同一句 SELECT value FROM STRING_SPLIT('a,b,c', ','),结果行序也可能变化。这不是 bug,是设计如此。
要拿到带序号的结果,必须显式启用 enable_ordinal = 1:
SELECT value, ordinal
FROM STRING_SPLIT('apple,banana,cherry', ',', 1)
ORDER BY ordinal;
注意:1 是 int 或 bit 类型,不能写成 '1' 或 NULL;传 0 或省略该参数,ordinal 列根本不会出现。
ORDER BY ordinal 不等于按原始位置排序,而是按函数内部编号
ordinal 是从 1 开始的连续整数,对应子串在输入字符串中的**出现顺序**,不是按字母或数值大小排。但这个“顺序”只在启用 enable_ordinal = 1 后才被保证。
常见错误写法:
- 漏掉第三个参数,却写
ORDER BY ordinal→ 报错 “无效的列名” - 写了
ORDER BY value→ 按字典序排,和原始位置无关 - 用
ORDER BY (SELECT NULL)包裹STRING_SPLIT→ 在 2022 中无效,ordinal不会自动产生
连续分隔符、空格、NULL 输入会影响 ordinal 编号逻辑
STRING_SPLIT 是机械切分,不跳过空项:输入 'a,,b' 会返回三行,ordinal 分别为 1、2、3,其中第二行 value 是空字符串(''),不是 NULL。
首尾空格也不会被自动清理:' a , b ' 的 value 值是 ' a ' 和 ' b ',ordinal 仍是 1 和 2。
处理建议:
- 过滤空值:
WHERE TRIM(value) '' - 清洗空格:
TRIM(value) AS clean_value - 处理 NULL 输入:
STRING_SPLIT(ISNULL(@input, ''), ','),因为传入NULL时函数直接返回空集,不报错但可能引发逻辑断裂
嵌套在 JOIN 或子查询里时,ordinal 无法被优化器下推
即使你用了 STRING_SPLIT(..., 1) 并拿到了 ordinal,一旦把它塞进 WHERE IN 或直接 JOIN,优化器仍无法利用 ordinal 做索引查找或谓词下推——它只是内存表的一列,没有统计信息。
更稳的做法是先落地:
SELECT TRIM(value) AS val, ordinal INTO #split FROM STRING_SPLIT(@csv, ',', 1) WHERE TRIM(value) '';
然后对 #split 建索引,并在后续 JOIN 中显式引用 ordinal 控制顺序或限制范围。否则,看似带序号,实际执行计划里还是可能乱序或性能骤降。
真正容易被忽略的是:ordinal 只解决“编号”问题,不解决“可预测性”——它依赖函数实现细节,不是事务安全的序列;并发高、输入超长(>4000 字符)、或跨数据库调用时,行为边界得靠实测确认,不能只信文档。










