SQL,from,将行分隔为列

时间:2017-04-25 22:49:49

标签: sql sql-server tsql

Create table test123
(
SeqId int,
string1 varchar(100),
string2 varchar(100)
)

insert into test123(SeqId,string1,string2)values
(10,'a,b,c','x,y,z'),
(20,'d,e,f','p,q,r')

输出

SeqId RowNum String1 String2
10  1   a   x
10  2   b   y
10  3   c   z
20  1   d   p
20  2   e   q
20  3   f   r

2 个答案:

答案 0 :(得分:3)

这将允许字符串中的可变/不均匀项目数。

几乎任何Split / Parse函数都可以。我提供了一个也提供该项目的序列号的。

选项1:没有解析功能

Declare @YourTable table (SeqId int,string1 varchar(100),string2 varchar(100))
insert into @YourTable values
(10,'a,b,c','x,y,z'),
(20,'d,e,f','p,q,r')

Select A.SeqId
      ,B.*
 From  @YourTable A
 Cross Apply (
                Select RowNum  = RetSeq
                      ,String1 = max(String1)
                      ,String2 = max(String2)
                 From (
                        Select RetSeq  = Row_Number() over (Order By (Select null))
                              ,String1 = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)')))
                              ,String2 = ''
                        From  (Select x = Cast('<x>' + replace((Select replace(A.String1,',','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A 
                        Cross Apply x.nodes('x') AS B(i)
                        Union All
                        Select RetSeq  = Row_Number() over (Order By (Select null))
                              ,String1 = ''
                              ,String2 = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)')))
                        From  (Select x = Cast('<x>' + replace((Select replace(A.String2,',','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A 
                        Cross Apply x.nodes('x') AS B(i)
                      ) B1
                 Group By RetSeq
             ) B

选项2:使用解析功能

Declare @YourTable table (SeqId int,string1 varchar(100),string2 varchar(100))
insert into @YourTable values
(10,'a,b,c','x,y,z'),
(20,'d,e,f','p,q,r')

Select A.SeqId
      ,B.*
 From  @YourTable A
 Cross Apply (
                Select RowNum = RetSeq
                      ,String1= max(String1)
                      ,String2= max(String2)
                 From (
                        Select RetSeq,String1=RetVal,String2='' from [dbo].[udf-Str-Parse](A.string1,',')
                        Union All
                        Select RetSeq,String1='',String2=RetVal from [dbo].[udf-Str-Parse](A.string2,',')
                      ) B1
                 Group By RetSeq

             ) B

返回

enter image description here

感兴趣的UDF

CREATE FUNCTION [dbo].[udf-Str-Parse] (@String varchar(max),@Delimiter varchar(25))
Returns Table 
As
Return (  
    with   cte1(N)   As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)),
           cte2(N)   As (Select Top (IsNull(DataLength(@String),0)) Row_Number() over (Order By (Select NULL)) From (Select N=1 From cte1 a,cte1 b,cte1 c,cte1 d) A ),
           cte3(N)   As (Select 1 Union All Select t.N+DataLength(@Delimiter) From cte2 t Where Substring(@String,t.N,DataLength(@Delimiter)) = @Delimiter),
           cte4(N,L) As (Select S.N,IsNull(NullIf(CharIndex(@Delimiter,@String,s.N),0)-S.N,8000) From cte3 S)

    Select RetSeq = Row_Number() over (Order By A.N)
          ,RetVal = LTrim(RTrim(Substring(@String, A.N, A.L)))
    From   cte4 A
);
--Orginal Source http://www.sqlservercentral.com/articles/Tally+Table/72993/
--Select * from [dbo].[udf-Str-Parse-8K]('Dog,Cat,House,Car',',')
--Select * from [dbo].[udf-Str-Parse-8K]('John||Cappelletti||was||here','||')

答案 1 :(得分:0)

使用动态SQL检查以下解决方案

&#13;
&#13;
declare @t table (SeqId int, string1 varchar(100), string2 varchar(100))

declare @result table(SeqId int, RowNum int, String1 varchar(10), String2 varchar(10))

declare @SeqId int

declare @string1 varchar(100)

declare @string2 varchar(100)

declare @char1 varchar(5)

declare @char2 varchar(5)

declare @count1 int

declare @count2 int

declare @rownum int


insert into @t select * from test123

while exists (select * from @t)
begin

select top 1 @SeqId = SeqId, @string1 = string1, @string2 = string2 from @t

set @rownum = 1

while @rownum <=3
begin

set @count1 = charindex(',',@string1,1) - 1

if @count1 < 0
	set @count1 = len(@string1)

set @count2 = charindex(',',@string2,1) - 1

if @count2 < 0
	set @count2 = len(@string2)

set @char1 = substring(@string1, 1, @count1)

set @char2 = substring(@string2, 1, @count2)

insert into @result values(@SeqId, @rownum, @char1, @char2)

set @string1 = substring(@string1, charindex(',',@string1,1)+1, len(@string1)-charindex(',',@string1,1))

set @string2 = substring(@string2, charindex(',',@string2,1)+1, len(@string2)-charindex(',',@string2,1))

set @rownum = @rownum + 1

end

delete top (1) from @t
end

select * from @result
&#13;
&#13;
&#13;