我有一个以下格式的字符串:
A:B:C;J:K;P:L:J;
我想在冒号(:)之后拆分字符串,并在分号(;)之后开始新的一行。谁能帮我查询。
输出示例:
A B C
J K
P L J
我有一个以下格式的字符串:
A:B:C;J:K;P:L:J;
我想在冒号(:)之后拆分字符串,并在分号(;)之后开始新的一行。谁能帮我查询。
输出示例:
A B C
J K
P L J
试试这个——
解决方案#1:
DECLARE @t VARCHAR(100)
SELECT @t = 'A:B:C;J:K;P:L:J;'
SELECT *
FROM (
SELECT token = t.c.value('.', 'VARCHAR(100)')
FROM
(
SELECT xmls = CAST('<t>' +
REPLACE(
REPLACE(@t, ':', ' '),
';',
'</t><t>') + '</t>' AS XML)
) r
CROSS APPLY xmls.nodes('/t') AS t(c)
) t
WHERE t.token != ''
输出:
----------
A B C
J K
P L J
解决方案#2:
DECLARE @t VARCHAR(100)
SELECT @t = 'A:B:C;J:K;P:L:J;'
PRINT REPLACE(REPLACE(@t, ':', ' '), ';', CHAR(13) + CHAR(13))
输出:
A B C
J K
P L J
解决方案#3:
DECLARE @t VARCHAR(100)
SELECT @t = 'A:B:C;J:K;P:L:J;'
SELECT [1], [2], [3]
FROM (
SELECT
t2.id
, t2.name
, rn2 = ROW_NUMBER() OVER (PARTITION BY t2.id ORDER BY 1/0)
FROM (
SELECT
id = t.c.value('@n', 'INT')
, name = t.c.value('@s', 'CHAR(1)')
FROM (
SELECT x = CAST('<t s = "' +
REPLACE(token + ':', ':', '" n = "' + CAST(rn AS VARCHAR(10))
+ '" /><t s = "') + '" />' AS XML)
FROM (
SELECT
token = t.c.value('.', 'VARCHAR(100)')
, rn = ROW_NUMBER() OVER (ORDER BY 1/0)
FROM (
SELECT x = CAST('<t>' + REPLACE(@t, ';', '</t><t>') + '</t>' AS XML)
) r
CROSS APPLY x.nodes('/t') t(c)
) t
) d
CROSS APPLY x.nodes('/t') t(c)
) t2
WHERE t2.name != ''
) t3
PIVOT (
MAX(name) FOR rn2 IN ([1], [2], [3])
) p
输出:
1 2 3
---- ---- ----
A B C
J K NULL
P L J
不确定,我理解正确,但是如果您需要将数据作为三列行集:
declare @str nvarchar(max)
set @str = 'A:B:C;J:K;P:L:J;'
select p.[1] as Column1, p.[2] as Column2, p.[3] as Column3
from (
select T.c.value('.', 'nvarchar(200)') [row], row_number() over (order by @@spid) rn1
from (select cast('<r>' + replace(@str, ';', '</r><r>') + '</r>' as xml) xmlRows) [rows]
cross apply xmlRows.nodes('/r') as T(c)
where T.c.value('.', 'nvarchar(200)') != ''
) t1
cross apply (
select NullIf(T.c.value('.', 'nvarchar(200)'), '') row2,
row_number() over (order by @@spid) rn
from (select cast('<r>' + replace(t1.row, ':', '</r><r>') + '</r>' as xml) xmlRows) [rows]
cross apply xmlRows.nodes('/r') as T(c)
) t2
pivot (max(t2.row2) for t2.rn in ([1], [2], [3])) p
order by p.rn1
输出
Column1 Column2 Column3
-------- -------- -------
A B C
J K NULL
P L J
SQL 中没有内置的 split 函数,但是您可以通过简单地运行这样的语句来自己创建函数。此解决方案可在您想要执行多部分拆分的其他情况下重复使用。
CREATE FUNCTION dbo.Split
(
@TextToSplit nvarchar(2000),
@SplitOn nvarchar(5)
)
RETURNS @RtnValue table
(
Id int identity(1,1),
Data nvarchar(100)
)
AS
BEGIN
Declare @Cnt int
Set @Cnt = 1
While (Charindex(@SplitOn,@TextToSplit)>0)
Begin
Insert Into @RtnValue (data)
Select
Data = ltrim(rtrim(Substring(@TextToSplit,1,Charindex(@SplitOn,@TextToSplit)- 1)))
Set @RowData = Substring(@TextToSplit,Charindex(@SplitOn,@TextToSplit)+1,len(@TextToSplit))
Set @Cnt = @Cnt + 1
End
Insert Into @RtnValue (data)
Select Data = ltrim(rtrim(@TextToSplit))
Return
END
然后你可以像这样运行它:
Declare @SplitThis as varchar(2000) = 'A:B:C;J:K;P:L:J'
DECLARE @Val as varchar(500)
DECLARE MyCursor CURSOR FAST_FORWARD FOR
select data from split(@SplitThis,';')
OPEN MyCursor
FETCH NEXT FROM MyCursor INTO @Val
WHILE @@FETCH_STATUS = 0
BEGIN
select(
select ' ' + data
from split(@Val,':')
for xml Path(''),type).value('.','varchar(100)') as cat
FETCH NEXT FROM MyCursor INTO @Val
END
CLOSE MyCursor
DEALLOCATE MyCursor
对于较大的字符串,我发现 UDF 循环方法比 xml 方法更有效。
create Function [Split_Text_Into_Table_Multi_Column] (
@Row_Delimit_Char Varchar(5)
,@Column_Delimit_Char Varchar(5)
,@Text_To_Split Varchar(Max) )
Returns
@Output_Table Table (
row_id Int Identity (1, 1)
,column_1 Varchar(Max) Collate Latin1_General_CS_AS
,column_2 Varchar(Max) Collate Latin1_General_CS_AS
,column_3 Varchar(Max) Collate Latin1_General_CS_AS
)
As
Begin
Declare
@Column_Delimit_Index_1 Int
,@Column_Delimit_Index_2 Int
,@String Varchar(Max)
,@String_1 Varchar(Max)
,@String_2 Varchar(Max)
,@String_3 Varchar(Max)
,@String_Len Int
,@Delimit_Len TinyInt
Declare
@Last_Delimit_Index Int = 0
,@Next_Delimit_Index Int = 1
--always treat new line as delimiter
Select
@Text_To_Split = Replace(Replace(@Text_To_Split, Char(10), @Row_Delimit_Char), Char(13), @Row_Delimit_Char)
--begin loop while next delimiter found
While @Next_Delimit_Index > 0
Begin
--find next delimiter
Select
@Next_Delimit_Index = CharIndex(@Row_Delimit_Char, @Text_To_Split, @Last_Delimit_Index + 1)
--get value to insert
Select
@String = Ltrim(Rtrim(Substring(@Text_To_Split, @Last_Delimit_Index + 1, Case
When @Next_Delimit_Index = 0 Then Len(@Text_To_Split) - @Last_Delimit_Index
Else @Next_Delimit_Index - @Last_Delimit_Index - 1
End)))
--Insert Non blank strings only
If @String <> ''
Begin
Select
@Delimit_Len = Len(@Column_Delimit_Char)
Select
@String_Len = DataLength(@String)/*includes trailing spaces*/
,@Column_Delimit_Index_1 = 1
,@Column_Delimit_Index_2 = IsNull(NullIf(CharIndex(@Column_Delimit_Char, @String, @Column_Delimit_Index_1), 0), @String_Len + 1)
,@String_1 =
Case
When @Column_Delimit_Index_2 <= @Column_Delimit_Index_1 Or
@Column_Delimit_Index_2 - @Column_Delimit_Index_1 = 0 Then Null
Else Substring(@String, @Column_Delimit_Index_1, @Column_Delimit_Index_2 - @Column_Delimit_Index_1)
End
,@Column_Delimit_Index_1 = @Column_Delimit_Index_2 + @Delimit_Len
,@Column_Delimit_Index_2 = IsNull(NullIf(CharIndex(@Column_Delimit_Char, @String, @Column_Delimit_Index_1), 0), @String_Len + 1)
,@String_2 =
Case
When @Column_Delimit_Index_2 <= @Column_Delimit_Index_1 Or
@Column_Delimit_Index_2 - @Column_Delimit_Index_1 = 0 Then Null
Else Substring(@String, @Column_Delimit_Index_1, @Column_Delimit_Index_2 - @Column_Delimit_Index_1)
End
,@Column_Delimit_Index_1 = @Column_Delimit_Index_2 + @Delimit_Len
,@Column_Delimit_Index_2 = IsNull(NullIf(CharIndex(@Column_Delimit_Char, @String, @Column_Delimit_Index_1), 0), @String_Len + 1)
,@String_3 =
Case
When @Column_Delimit_Index_2 <= @Column_Delimit_Index_1 Or
@Column_Delimit_Index_2 - @Column_Delimit_Index_1 = 0 Then Null
Else Substring(@String, @Column_Delimit_Index_1, @Column_Delimit_Index_2 - @Column_Delimit_Index_1)
End
Insert Into
@Output_Table (
column_1
,column_2
,column_3)
Values
(
@String_1
,@String_2
,@String_3)
End
--set last last char index
Select
@Last_Delimit_Index = @Next_Delimit_Index
End
Return
End
--sample output
Select *
from [Split_Text_Into_Table_Multi_Column] (',',' ','
917064578 70
917581826 66
917635915 66
917663205 66
918320481 66
918752247 ER
918892315 70
919162748 52
919169913 JS
919169927 70
919187495 52
919207137 52
919226194 70
919252530 52
919252544 KG
919269942 52
919269957 KG
919269961 47
')
输出
row_id|column_1|column_2|column_3
1|917064578|70|NULL
2|917581826|66|NULL
3|917635915|66|NULL
4|917663205|66|NULL
5|918320481|66|NULL
6|918752247|ER|NULL
7|918892315|70|NULL
8|919162748|52|NULL
9|919169913|JS|NULL
10|919169927|70|NULL
11|919187495|52|NULL
12|919207137|52|NULL
13|919226194|70|NULL
14|919252530|52|NULL
15|919252544|KG|NULL
16|919269942|52|NULL
17|919269957|KG|NULL
18|919269961|47|NULL