SQL Server 2016及以上版本中,能否用STRING_SPLIT返回指定位置的值?
关于SQL Server中STRING_SPLIT的顺序与特定位置取值问题
咱们先把你的两个核心问题拆解开来回答:
1. STRING_SPLIT的结果顺序是否有保证?
这个得分版本看:
- 在SQL Server 2016到2019版本中:官方明确说明,
STRING_SPLIT返回的结果顺序是不固定、无保证的——哪怕你输入的字符串是按z_y_x这种明确顺序写的,输出的value列也可能乱序,完全不能依赖它的输出顺序来判断元素位置。 - 在**SQL Server 2022(以及Azure SQL)**中:
STRING_SPLIT新增了enable_ordinal参数,当你传入1时,函数会额外返回一个ordinal列,这个列严格对应元素在原字符串中的位置(比如z_y_x分割后,z的ordinal是1,y是2,x是3),此时顺序是100%可靠的。
2. 能否用STRING_SPLIT返回特定位置的值?
同样分版本处理:
针对SQL Server 2022+/Azure SQL
这就很简单了,直接用带enable_ordinal参数的STRING_SPLIT,过滤ordinal等于目标位置就行:
DROP TABLE IF EXISTS #split SELECT 'z_y_x' AS splitIt INTO #split UNION SELECT 'a_b_c' -- 提取每个字符串的第2个元素 SELECT s.splitIt, ss.value FROM #split s CROSS APPLY STRING_SPLIT(s.splitIt, '_', 1) ss WHERE ss.ordinal = 2
执行后会得到z_y_x对应的y,a_b_c对应的b,完全符合预期。
针对SQL Server 2016-2019
因为这个版本的STRING_SPLIT没有位置列,而且顺序无保证,你原来用ROW_NUMBER()的方法其实有问题——你在窗口函数里写ORDER BY s.splitIt,但同一个splitIt的所有分割行,这个排序字段是完全一样的,数据库会随机分配行号,根本没法对应真实的元素位置。
推荐用OPENJSON来替代,它在处理字符串拆分时会严格保留原顺序,而且是2016版本就支持的:
DROP TABLE IF EXISTS #split SELECT 'z_y_x' AS splitIt INTO #split UNION SELECT 'a_b_c' -- 提取每个字符串的第2个元素(OPENJSON的key从0开始,所以+1对应第2位) SELECT s.splitIt, oj.value FROM #split s CROSS APPLY OPENJSON('["' + REPLACE(s.splitIt, '_', '","') + '"]') oj WHERE CAST(oj.[key] AS INT) + 1 = 2
这个方法的原理是把原字符串转成JSON数组,OPENJSON会给每个元素分配从0开始的key,对应原字符串的顺序,所以过滤key+1就能拿到指定位置的元素。
当然你也可以用SUBSTRING+CHARINDEX的组合来写自定义函数,但OPENJSON的写法更简洁通用。
内容的提问来源于stack exchange,提问作者Stagg
相关产品推荐
相关产品推荐

