这是恢复 67 的最简单答案(type-safe!!):
SELECT CAST('<x>' + REPLACE('1,222,2,67,888,1111',',','</x><x>') + '</x>' AS XML).value('/x[4]','int')
在下文中,您将找到示例如何将其与字符串、分隔符和位置的变量一起使用(即使对于带有 XML 禁止字符的边缘情况)
简单的
这个问题不是关于字符串拆分方法,而是关于如何获取第 n 个元素。最简单、完全可内联的方式就是这个 IMO:
这是一个真正的单行,以空格分隔第 2 部分:
DECLARE @input NVARCHAR(100)=N'part1 part2 part3';
SELECT CAST(N'<x>' + REPLACE(@input,N' ',N'</x><x>') + N'</x>' AS XML).value('/x[2]','nvarchar(max)')
变量可以与sql:variable() 或sql:column() 一起使用
当然您可以使用变量作为分隔符和位置(使用sql:column 直接从查询值中检索位置):
DECLARE @dlmt NVARCHAR(10)=N' ';
DECLARE @pos INT = 2;
SELECT CAST(N'<x>' + REPLACE(@input,@dlmt,N'</x><x>') + N'</x>' AS XML).value('/x[sql:variable("@pos")][1]','nvarchar(max)')
带有 XML 禁止字符的 Edge-Case
如果您的字符串可能包含禁止字符,您仍然可以这样做。只需先在字符串上使用FOR XML PATH,即可将所有禁用字符隐式替换为合适的转义序列。
如果 - 另外 - 您的分隔符是分号,这是一个非常特殊的情况。在这种情况下,我首先将分隔符替换为“#DLMT#”,最后将其替换为 XML 标记:
SET @input=N'Some <, > and &;Other äöü@€;One more';
SET @dlmt=N';';
SELECT CAST(N'<x>' + REPLACE((SELECT REPLACE(@input,@dlmt,'#DLMT#') AS [*] FOR XML PATH('')),N'#DLMT#',N'</x><x>') + N'</x>' AS XML).value('/x[sql:variable("@pos")][1]','nvarchar(max)');
SQL-Server 2016+ 更新
很遗憾,开发人员忘记返回带有STRING_SPLIT 的部件索引。但是,使用 SQL-Server 2016+,有 JSON_VALUE 和 OPENJSON。
使用JSON_VALUE,我们可以将位置作为索引数组传递。
对于OPENJSON,documentation 明确说明:
当 OPENJSON 解析 JSON 数组时,该函数返回 JSON 文本中元素的索引作为键。
像1,2,3 这样的字符串只需要括号:[1,2,3]。
像this is an example 这样的一串单词必须是["this","is","an"," example"]。
这些是非常简单的字符串操作。试试看吧:
DECLARE @str VARCHAR(100)='Hello John Smith';
DECLARE @position INT = 2;
--We can build the json-path '$[1]' using CONCAT
SELECT JSON_VALUE('["' + REPLACE(@str,' ','","') + '"]',CONCAT('$[',@position-1,']'));
--查看这个位置安全的字符串拆分器(从零开始):
SELECT JsonArray.[key] AS [Position]
,JsonArray.[value] AS [Part]
FROM OPENJSON('["' + REPLACE(@str,' ','","') + '"]') JsonArray
在this post我测试了各种方法,发现OPENJSON真的很快。甚至比著名的“delimitedSplit8k()”方法还要快...
更新 2 - 获取类型安全的值
我们可以在数组中使用数组,只需使用双倍的[[]]。这允许输入WITH-clause:
DECLARE @SomeDelimitedString VARCHAR(100)='part1|1|20190920';
DECLARE @JsonArray NVARCHAR(MAX)=CONCAT('[["',REPLACE(@SomeDelimitedString,'|','","'),'"]]');
SELECT @SomeDelimitedString AS TheOriginal
,@JsonArray AS TransformedToJSON
,ValuesFromTheArray.*
FROM OPENJSON(@JsonArray)
WITH(TheFirstFragment VARCHAR(100) '$[0]'
,TheSecondFragment INT '$[1]'
,TheThirdFragment DATE '$[2]') ValuesFromTheArray