MS SQL Server:提取逗号分隔字符串中指定位置的值
拆分带前缀逗号的分隔字符串并提取指定位置值的简便方法
针对你的需求,我整理了两种实用方案,都能实现像SELECT * FROM Value(N)这样调用提取任意位置值的效果,同时完美处理NULL和位置不存在的场景:
方案一:兼容全版本的字符串定位法(推荐老版本SQL Server)
这个方案用原生字符串函数实现,不依赖高版本特性,且能严格保证提取顺序和原字符串一致:
首先创建自定义函数:
CREATE FUNCTION dbo.Value(@position INT) RETURNS TABLE AS RETURN ( SELECT Id, CASE -- 处理NULL输入或非法位置参数 WHEN Val IS NULL OR @position <= 0 THEN NULL ELSE -- 把空字符串转为NULL,对应位置不存在的情况 NULLIF( SUBSTRING( Val, -- 定位第@position个逗号的位置,取其后一位作为起始点 CHARINDEX(',', Val, CHARINDEX(',', Val, 1) * (@position - 1)) + 1, -- 定位下一个逗号的位置,计算截取长度 CHARINDEX(',', Val + ',', CHARINDEX(',', Val, CHARINDEX(',', Val, 1) * (@position - 1)) + 1) - (CHARINDEX(',', Val, CHARINDEX(',', Val, 1) * (@position - 1)) + 1) ), '' ) END AS Val FROM Table1 )
逻辑说明:
- 先判断
Val为NULL或传入的位置参数小于等于0,直接返回NULL - 给原字符串末尾拼接一个逗号,避免最后一个值后面无逗号导致截取失败
- 用嵌套的
CHARINDEX定位目标位置的前后逗号,再用SUBSTRING截取中间内容 - 最后用
NULLIF把截取到的空字符串转为NULL,对应位置不存在的场景(比如第1行调用Value(2))
测试效果:
调用SELECT * FROM dbo.Value(1):
| Id | Val |
|---|---|
| 1 | 4 |
| 2 | 3 |
| 3 | NULL |
| 4 | 5 |
调用SELECT * FROM dbo.Value(2):
| Id | Val |
|---|---|
| 1 | NULL |
| 2 | 1 |
| 3 | NULL |
| 4 | 2 |
方案二:简洁的拆分函数法(适合SQL Server 2016+)
如果你的数据库是SQL Server 2016及以上版本,可以用STRING_SPLIT函数简化代码,不过要注意:官方文档说明STRING_SPLIT不保证输出顺序和原字符串完全一致(实际测试中大多是一致的,但需要绝对可靠顺序的话,建议用方案一):
创建自定义函数:
CREATE FUNCTION dbo.Value(@position INT) RETURNS TABLE AS RETURN ( WITH SplitCTE AS ( SELECT Id, value, -- 给每个Id的拆分值按顺序编号 ROW_NUMBER() OVER (PARTITION BY Id ORDER BY (SELECT NULL)) AS rn FROM Table1 CROSS APPLY STRING_SPLIT(Val, ',') WHERE value <> '' -- 过滤开头逗号产生的空字符串 ) SELECT t.Id, s.value AS Val FROM Table1 t LEFT JOIN SplitCTE s ON t.Id = s.Id AND s.rn = @position )
逻辑说明:
- 用
CROSS APPLY STRING_SPLIT拆分字符串,过滤掉开头逗号产生的空值 - 用
ROW_NUMBER给每个Id下的有效拆分值编号 - 左连接原表,匹配对应位置的编号,没有匹配到就返回
NULL
测试效果和方案一完全一致,代码更简洁。
内容的提问来源于stack exchange,提问作者ihorko
相关产品推荐
相关产品推荐

