2013-07-18 27 views

回答

4

不知道,我理解正確的,但如果你需要數據,三列行集:

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 
+0

該解決方案不是一般的。給定列分隔符和行分隔符,它不能將任何字符串拆分爲表格。它不會處理該字符串A:B:C:X; J:K:X; P:L:J:X; (增加第4欄)。 –

7

嘗試這一個 -

溶液#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 
+0

@rahul AGGARWAL,可以請你告訴什麼是錯誤的,我的答案嗎? – Devart

+0

答案是正確的,但在上面的解決方案中,輸出顯示在3個不同的列中。感謝您的解決方案 –

+0

@rahul aggarwal,請參閱最新的答案。 – Devart

1

在SQL中沒有內置的分割函數,但是您可以通過簡單地運行像這樣的語句來創建函數。在您想要執行多部分拆分的其他情況下,此解決方案可重複使用。

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 
+0

祝你的項目好運。 – Brian

1

對於較大的字符串,我發現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