我有一个大字符串(nvarchar(MAX)
),我试图将其拆分为2,并确定它们是原始字符串的哪一部分。
示例
字符串:
5;718;0;1071;1.23|0;750;0;997;1.25|0;750;0;997;1.25|0;750;0;997;1.25|0;750;0;997;1.25|0;750;0;997;1.25
我首先需要根据'|'
字符拆分字符串,如下所示:
5;718;0;1071;1.23
0;750;0;997;1.25
0;750;0;997;1.25
0;750;0;997;1.25
0;750;0;997;1.25
0;750;0;997;1.25
然后我将根据';'
字符对每个字符进行拆分:
因此,5;718;0;1071;1.23
将拆分为:
5
718
0
1071
1.23
我知道我可以在'|'
上进行一个string_split,然后在';'上进行另一个string_split。但这并不能保持顺序,也无法确定结果是从字符串的哪一部分中分离出来的,很不幸,当尝试使用OPENJSON()
时,我无法完全获得所需的结果:
基于上面的示例,我需要一个可以识别718
来自第一组和第二组的结果。
答案 0 :(得分:2)
这是一个可以解析您的字符串并保持顺序的选项
示例
Declare @S varchar(max) = '5;718;0;1071;1.23|0;750;0;997;1.25|0;750;0;997;1.25|0;750;0;997;1.25|0;750;0;997;1.25|0;750;0;997;1.25'
Select Seq1 = A.RetSeq
,Val1 = A.RetVal
,Seq2 = B.RetSeq
,Val2 = B.RetVal
From [dbo].[tvf-Str-Parse](@S,'|') A
Cross Apply [dbo].[tvf-Str-Parse](A.RetVal,';') B
返回
感兴趣的功能
CREATE FUNCTION [dbo].[tvf-Str-Parse] (@String varchar(max),@Delimiter varchar(10))
Returns Table
As
Return (
Select RetSeq = row_number() over (order by 1/0)
,RetVal = ltrim(rtrim(B.i.value('(./text())[1]', 'varchar(max)')))
From (Select x = Cast('<x>' + replace((Select replace(@String,@Delimiter,'§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A
Cross Apply x.nodes('x') AS B(i)
);
编辑-更新表
Declare @YourTable table (ID int,SomeCol varchar(max))
Insert Into @YourTable values
(1,'5;718;0;1071;1.23|0;750;0;997;1.25|0;750;0;997;1.25|0;750;0;997;1.25|0;750;0;997;1.25|0;750;0;997;1.25')
Select A.ID
,Seq1 = B.RetSeq
,Val1 = B.RetVal
,Seq2 = C.RetSeq
,Val2 = C.RetVal
From @YourTable A
Cross Apply [dbo].[tvf-Str-Parse](SomeCol,'|') B
Cross Apply [dbo].[tvf-Str-Parse](B.RetVal,';') C
答案 1 :(得分:0)
这是我的旧学校照:
declare @v nvarchar(max) = N'5;718;0;1071;1.23|0;750;0;997;1.25|0;750;0;997;1.25|0;750;0;997;1.25|0;750;0;997;1.25|0;750;0;997;1.25'
select a.value('.', 'nvarchar(max)') [value], v2.col, rnInternal,ROW_NUMBER() over(partition by rnInternal order by rnInternal, Split.a) rnExternal
from
(
select cast('<M>' + REPLACE(v.[value], ';', '</M><M>') + '</M>' AS XML) as col, rnInternal
from
(
select
a.value('.', 'nvarchar(max)') [value],
ROW_NUMBER() over(order by Split.a) rnInternal
from
(select cast('<M>' + REPLACE(@v, '|', '</M><M>') + '</M>' AS XML) as col) as A
CROSS APPLY A.col.nodes ('/M') AS Split(a)
where
a.value('.', 'nvarchar(max)') <> ''
) v
) v2
CROSS APPLY v2.col.nodes ('/M') AS Split(a)
order by rnInternal, rnExternal
答案 2 :(得分:0)
您对STRING_SPLIT()
是正确的(如documentation 输出行可以按任何顺序所述),但是您可以使用基于JSON的方法获得预期的结果。
您需要将输入文本转换为有效的嵌套JSON数组(将5;718;0;1071;1.23|0;750;0;997;1.25|
转换为[[5,718,0,1071,1.23],[0,750,0,997,1.25]]
),并使用默认模式通过两次OPENJSON()
调用来解析此数组。 OPENJSON()
调用的结果是一个包含列key
,value
和type
的表,如果是JSON数组,则key
列返回索引的索引。指定数组中的元素:
DECLARE @text nvarchar(max) = N'5;718;0;1071;1.23|0;750;0;997;1.25|0;750;0;997;1.25|0;750;0;997;1.25|0;750;0;997;1.25|0;750;0;997;1.25'
SELECT
CONVERT(int, j1.[key]) + 1 AS id1,
CONVERT(int, j2.[key]) + 1 AS id2,
j2.[value]
FROM OPENJSON(CONCAT('[[', REPLACE(REPLACE(@text, '|', '],['), ';', ','), ']]')) j1
CROSS APPLY OPENJSON(j1.[value]) j2
ORDER BY CONVERT(int, j1.[key]), CONVERT(int, j2.[key])
结果:
id1 id2 value
1 1 5
1 2 718
1 3 0
1 4 1071
1 5 1.23
2 1 0
2 2 750
...
6 1 0
6 2 750
6 3 0
6 4 997
6 5 1.25
如果要标识每个组和子组的ID,则需要添加适当的WHERE
子句:
SELECT
CONVERT(int, j1.[key]) + 1 AS id1,
CONVERT(int, j2.[key]) + 1 AS id2
FROM OPENJSON(CONCAT('[[', REPLACE(REPLACE(@text, '|', '],['), ';', ','), ']]')) j1
CROSS APPLY OPENJSON(j1.[value]) j2
WHERE j2.[value] = '718'
ORDER BY CONVERT(int, j1.[key]), CONVERT(int, j2.[key])
结果:
id1 id2
1 2