2017-10-16 34 views
3

我需要拆分由波浪號(〜)字符分隔的列中的值,但對於單個行中的多個列。我可以使用XML拆分一列,但是我在解決如何拆分多列時遇到問題。SQL Server中如何拆分多個列中的字符上的字符串

這是一個行目前看起來是這樣的:

Column1 Column2    Column3     Column4  
[JJ2222] [~BLUE~BROWN~BLACK] [~BB1234~BC2345~BD3456] [~BLUE, BABY (BB1234)~BROWN, COW (BC2345)~BLACK, DOG (BD3456)] 

拆分後,我期待與錨(JJ2222)排列所有的值多行:

Column1 Column2 Column3 Column4 
JJ2222 BLUE  BB1234 BLUE, BABY (BB1234) 
JJ2222 BROWN BC2345 BROWN, COW (BC2345) 
JJ2222 BLACK BD3456 BLACK, DOG (BD3456) 

在我的知識有限,我可能會創建3個獨立的查詢,將每列分別加載到臨時表中,然後將每個表加入到Column1中,但我希望有一種方法可以在一個查詢中完成。

+2

有幾十個重複說相同:*避免*首先插入這些值。加載數據時拆分字符串要容易得多。您不能索引或搜索這些列。 SQL Server在2016年添加了一個'STRING_SPLIT'命令,可用於清理這些條目 –

+0

Panagiotis - 感謝您的建議。是的,我熟悉2016年添加的String_Split函數,但不幸的是,此版本是2012. –

回答

1

有很多關於如何拆分字符串的例子。這裏的技巧是鏈接或連接序列。

如果打開到UDF

Select A.Column1 
     ,B.* 
From YourTable A 
Cross Apply (
       Select Column2=B1.RetVal 
         ,Column3=B2.RetVal 
         ,Column4=B3.RetVal 
       From [dbo].[tvf-Str-Parse](A.Column2,'~') B1 
       Join [dbo].[tvf-Str-Parse](A.Column3,'~') B2 on B1.RetSeq=B2.RetSeq 
       Join [dbo].[tvf-Str-Parse](A.Column4,'~') B3 on B1.RetSeq=B3.RetSeq 
       Where B1.RetVal is not null 
        and B2.RetVal is not null 
        and B3.RetVal is not null 
      ) B 

返回

Column1 Column2 Column3 Column4 
JJ2222 BLUE BB1234 BLUE, BABY (BB1234) 
JJ2222 BROWN BC2345 BROWN, COW (BC2345) 
JJ2222 BLACK BD3456 BLACK, DOG (BD3456) 

的UDF如果有意

CREATE FUNCTION [dbo].[tvf-Str-Parse] (@String varchar(max),@Delimiter varchar(10)) 
Returns Table 
As 
Return ( 
    Select RetSeq = Row_Number() over (Order By (Select null)) 
      ,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) 
); 
--Thanks Shnugo for making this XML safe 
--Select * from [dbo].[tvf-Str-Parse]('Dog,Cat,House,Car',',') 
--Select * from [dbo].[tvf-Str-Parse]('John Cappelletti was here',' ') 
+0

謝謝John!你的腳本工作完美。它完全符合我的要求。 –

+0

@RonnieJ樂於助人 –

0

這是我非常喜歡Jeff Moden的分配器的那個時代。 http://www.sqlservercentral.com/articles/Tally+Table/72993/它是我所知道的唯一一個分隔符,它返回每個元素的序數位置,而不是循環。正如評論中所述,不存儲這樣的數據是迄今爲止最好的選擇,如果可能的話。要解決這個問題,你必須拆分每一列。

這件事應該適合你。它適用於您的示例數據。

declare @Something table 
(
    Column1 varchar(20) 
    , Column2 varchar(50) 
    , Column3 varchar(50) 
    , Column4 varchar(500) 
) 

insert @Something 
select 'JJ2222', '~BLUE~BROWN~BLACK', '~BB1234~BC2345~BD3456', '~BLUE, BABY (BB1234)~BROWN, COW (BC2345)~BLACK, DOG (BD3456)' 
; 

select s.Column1 
    , c2.Item 
    , c3.Item 
    , c4.Item 
from @Something s 
cross apply dbo.DelimitedSplit8K(s.Column2, '~') c2 
cross apply dbo.DelimitedSplit8K(s.Column3, '~') c3 
cross apply dbo.DelimitedSplit8K(s.Column4, '~') c4 
where c2.Item > '' --this eliminates an empty row because you have the delimiter at the beginning of the string. 
    and c2.ItemNumber = c3.ItemNumber 
    and c2.ItemNumber = c4.ItemNumber 
1

由於擰緊已經在那裏,它不會幫助它成爲一個不同的(稍小一點)。你需要的是將這些數據分成不同的表格。

除第1列之外的所有內容都需要成爲另一個表的外鍵。

對於原始表格中列中每個項目的組合,可以使用適當的附加表格。每個這些表的樣子:

CombinationId,價值

當你有例如:

[~BLUE~BROWN~BLACK] 

你把它分解成附加表組合2所示:

CombinationId Value 

1 BLUE 

1 BROWN 

1 BLACK 

你做這爲原始表的所有列。當你爲每一列逐行處理原始表格時,你檢查你創建CombinationsX的新表格是否已經有組合,就像共享相同的ID一樣。如果是這樣,你把這個Id放在原始表中。如果沒有,則將該組合添加到新索引中,並將該數字作爲外鍵放入原始表中。

您現在已將您的數據分成多個表並使其可用。

你從現在開始想做什麼不同,但至少現在你可以將它改造成不同的東西。至少現在你可以查詢數據,搜索,索引等等。當你不用垃圾填充它時,你期望從數據庫中提供的東西;)

相關問題