1. 程式人生 > >用SQL將字串按分隔符拆為子串

用SQL將字串按分隔符拆為子串

專案中同一個型號包含多個尺碼資訊,這些資訊採用分隔符拼接在一起存放在一個欄位中,現在需要提交每個型號的各個尺碼資訊,也就是說原來一條記錄儲存的,現在需要變成多條記錄。下面給出原始表和插入資料的指令碼:

create table A(Lot_Key varchar(15),    F_Size varchar(100))
 
insert into A
select 'CA101',    '33.50x1.50x2.50x3.35' union all
select 'CA200',    '18.50x17.00x1.60' union all
select 'CG300',    '21.15x1.65x2.50x1.30x1.65' union all
select 'CQ255',    '31.50x1.75'
go

查詢A表中的資料得到如下結果:

                               圖 1

期望的結果是每條記錄的F_Size按照x進行分隔,轉化成多條記錄,最終得到如下結果:

                               圖2

這裡考慮採用SUBSTRING函式取子串的方式獲取每個尺碼,引入master..spt_values表,通過該表可以獲取0到2047總共2048個連續的數字,這樣可以定位每個分隔符的索引位置,實現兩個分隔符之間數字的擷取。下面是查詢上圖結果的SQL語句:

select Lot_Key,F_Size,
       MAX(case when rownum = 1 then v else null end) F_Size01,
       MAX(case when rownum = 2 then v else null end) F_Size02,
       MAX(case when rownum = 3 then v else null end) F_Size03,
       MAX(case when rownum = 4 then v else null end) F_Size04,
       MAX(case when rownum = 5 then v else null end) F_Size05          
from 
(
    select Lot_Key,
	 F_Size,
	 SUBSTRING(t.F_Size, number ,CHARINDEX('x',t.F_Size+'x',number)-number) as v,
	 ROW_NUMBER() over(partition by lot_key order by getdate()) rownum
    from A t,master..spt_values s
    where s.number >=1
    and s.type = 'P'
    and SUBSTRING('x'+t.F_Size,s.number,1) = 'x'
)t
group by Lot_Key,F_Size
order by Lot_Key

上面的SQL語句理解起來非常困難,那麼我們抽絲剝繭看它是如何進行字串分隔的。首先看下面的SQL語句:
select * from  A t,master..spt_values s
where s.number >=1
and s.type = 'P'
and SUBSTRING('x'+t.F_Size,s.number,1) = 'x' 

得到的結果:

                                                           圖3

原來的CA101記錄變成了4條記錄,注意number列,1,7,12,17分別是每個分隔符的位置,當然是針對“x33.50x1.50x2.50x3.35”而言。圖3中的記錄數和最終的結果的記錄數是一致的,這個時候就需要在圖3中每個F_Size資料後面加一個x,例如圖3中的第一條記錄為例,就變成了“33.50x1.50x2.50x3.35x”,每次需要首先知道要取的子串的長度,採用下面的語句:

select CHARINDEX('x',t.F_Size+'x',number)-number

以圖3中的第一條記錄為例對上面的語句進行轉化

最終再看看如何取出子串數字

總結

這種方式只能針對字串的長度在一定限度範圍內的,否則就會因master..spt_values表的連續自然數不足,導致後面的沒辦法分割。