在數(shù)據(jù)庫(kù)開(kāi)發(fā)過(guò)程中,字符串和關(guān)系表的轉(zhuǎn)化是一項(xiàng)基本技能。當(dāng)字符串中存在分隔符時(shí),有時(shí)將其轉(zhuǎn)換成關(guān)系表數(shù)據(jù),和其他數(shù)據(jù)表進(jìn)行join查詢,出現(xiàn)這種情況,是因?yàn)闆](méi)有遵守關(guān)系數(shù)據(jù)庫(kù)的設(shè)計(jì)范式,沒(méi)有把字符串拆分成原子項(xiàng)存儲(chǔ),也有可能是數(shù)據(jù)傳參數(shù);有時(shí)會(huì)遇到相反的情況,需要將關(guān)系表的相關(guān)數(shù)據(jù)拼接成一個(gè)字符串顯示,或傳參。
把格式化的字符串轉(zhuǎn)化成關(guān)系格式,基本思路分為兩種:
利用TSQL的循環(huán)語(yǔ)句:每一次循環(huán)都插入到關(guān)系表變量或臨時(shí)表中,這種思路是面向過(guò)程的編程;
使用XML查詢:先把字符串轉(zhuǎn)化成XML格式,再利用XML的nodes()函數(shù),把XML數(shù)據(jù)轉(zhuǎn)化成關(guān)系數(shù)據(jù);這種思路是面向集合的編程,建議采用XML查詢實(shí)現(xiàn);
把關(guān)系格式轉(zhuǎn)化成字符串,基本思路分為兩種:
利用TSQL的游標(biāo),對(duì)字符串執(zhí)行累加連接,這種思路是面向過(guò)程的編程;
利用XML查詢的for xml path子句,把關(guān)系格式轉(zhuǎn)化成字符串;這種思路是面向集合的編程,建議采用XML查詢實(shí)現(xiàn);
一,將字符串轉(zhuǎn)換成表
先把字符串轉(zhuǎn)換成XML格式,再利用XML的nodes()函數(shù),把XML數(shù)據(jù)轉(zhuǎn)化成關(guān)系數(shù)據(jù),這種實(shí)現(xiàn)方式性能快,代碼簡(jiǎn)潔,
declare @separator varchar(10)declare @str varchar(max) set @separator=','set @str='54,57,55,56,59'
1,把字符串轉(zhuǎn)化成節(jié)點(diǎn)值
declare @xml xmlset @xml=convert(xml,'<v>' + REPLACE(@str, @separator, '</v><v>') + '</v>')SELECT ids=N.v.value('.', 'int') FROM @xml.nodes('/v') N(v)
2,把字符串轉(zhuǎn)化成節(jié)點(diǎn)屬性
declare @xml xmlset @xml=convert(xml,'<Item v=''' + REPLACE(@str, @separator, '''></Item><Item v=''') + '''></Item>') SELECT ids=N.v.value('@v', 'int') FROM @xml.nodes('/Item') N(v)
3,內(nèi)置表值函數(shù)(string_split)
SQL Server 2016 新增一個(gè)表值函數(shù)string_split,用于按照分隔符將字符串分割成表值數(shù)據(jù),返回的字段名是Value
STRING_SPLIT ( string , separator )
二,將表數(shù)據(jù)拼接成字符串
有以下數(shù)據(jù)表,有兩列:ID和txt,ID值有重復(fù),而txt是文本數(shù)據(jù);
create table dbo.test ( ID int, txt varchar(10) )
把ID字段相同的txt字段的值拼接成字符串顯示
select ID ,(select a.txt+'' from dbo.test a where a.ID=t.ID for xml path('')) as descrfrom dbo.test t group by ID
三,奇巧淫技
在master數(shù)據(jù)庫(kù)中,存在一個(gè)系統(tǒng)視圖:master.dbo.spt_values,該視圖包含從0到2047的所有數(shù)字,利用這個(gè)特性,可以把特定長(zhǎng)度的字符串轉(zhuǎn)化成關(guān)系格式,實(shí)現(xiàn)的代碼如下:
;with cte_numbers as ( select number from master.dbo.spt_values where type='p' and number>0)select cast(substring(@str, n.number, charindex(@separator ,@str +@separator ,n.number )-n.number) as nvarchar(4000)) as item --,n.number from cte_numbers n where n.number<=len(@str)+1 and charindex(@separator,@separator+@str,n.number)=n.number
對(duì)于該方法,要體會(huì)其代碼的思路,通過(guò)數(shù)據(jù)序列,從數(shù)字1開(kāi)始,逐個(gè)檢測(cè)分隔符,對(duì)字符串進(jìn)行分割操作,由于master.dbo.spt_values只有0到2047個(gè)順序數(shù)字,在必要時(shí),可以替換該系統(tǒng)視圖,而使用自定義的數(shù)據(jù)序列表,以增加能夠拆分的字符串長(zhǎng)度。
參考文檔:
Why (and how) to split column using master..spt_values?
--業(yè)精于勤而荒于嬉,行成于思而毀于隨--
--歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)注明出處--
http://www.cnblogs.com/ljhdo/p/4789343.html