使用 FOR XML PATH 合并SQL Server查询结果的重复行
參考資料:
http://www.cnblogs.com/doubleliang/archive/2011/07/06/2098775.html
http://www.cnblogs.com/codeyu/archive/2010/05/25/1743474.html
核心摘要
FOR XML PATH 的作用是把結(jié)果以xml文本的形式顯示出來,也就是說,最終結(jié)果就是一個字符串,因此我們就不需要使用什么字符串合并函數(shù)了。
STUFF函數(shù)的原型是?Stuff(str1, start, len, str2),作用是,刪掉str1中start開始的len個字符,用str2替換。因此,可以起到在多個項之間插入分隔符。
比如,
select ','+name from student for xml path('') group by class輸出結(jié)果可能是
,Jim,Kate,Tom,Sally
如果使用STUFF,可以刪掉第一個空格
stuff(select ','+name from student for xml path('') group by class, 1, 1, '')?
原文內(nèi)容
-------------參考------------------------
----假設我們有如下數(shù)據(jù)表
------菜系表------------
--店名??????? 菜系------
--澳門豆撈??? 川菜?
--澳門豆撈??? 粵菜?
--澳門豆撈??? 閩菜?
--為民大酒店? 魯菜?
--為民大酒店? 粵菜?
--為民大酒店? 川菜
-----------------------
-------執(zhí)行如下語句
select?店名,菜系=STUFF((select?','+ltrim(菜系)?from?菜系表?where?店名=t.店名?for?XML path('')),1,1,'')
from?菜系表 t
group?by?店名
-------結(jié)果如下-------------
--店名??????? 菜系----------
--澳門豆撈??? 川菜,閩菜,粵菜
--為民大酒店? 川菜,魯菜,粵菜
----------------------------
--------------------------------------------------------------------------------------
Stuff(expression1_Str,startIndex,lengthInt,expression2_Str)函數(shù)共有四個參數(shù),
其功能是將expression1_Str中自startIndex位置起刪除lengthInt個字符,然后將expression2插入到expression1_Str中的startIndex位置。startIndex 從1開始
數(shù)據(jù)庫表中有三個字段,要以xxxx-xxxxxx-xxxxxx的格式輸出,其中不滿相應位數(shù)的,在后面補空格,即把類似23,1234,879這樣的三個數(shù)以如下形式輸出到報表中:23__-1234__-879___的格式輸出,標注顏色的下劃線一種顏色代表一個空格。?
STUFF(SPACE(4),1,LEN(‘23’),’23’)+’-’+STUFF(SPACE(6),1,LEN(‘1234’),’1234’)+’-’+?STUFF(SPACE(6),1,LEN(‘879’),’879’),轉(zhuǎn)換結(jié)果自然就為23__-1234__-879___了。
Stuff函數(shù)另一種解釋
select?stuff('string1',<starting position>,<length?to?delete?from?string?1>,'string2')
示例:
select?stuff('youxiaofeng',2,1,'F')
從第二個字符開始,刪掉一個字符,然后用'F'代替刪掉字符的位置,如果不需要刪掉字符,則將<length?to?delete?from?string?1>設為0即可。
注意:如果<starting position>或<length?to?delete?from?string?1?>是負的,或者<starting position>是大于<string?1>長度的數(shù),則STUFF函數(shù)將返回NULL,如果指令的<length?to?delete?from?string?1>長于從<starting position>位置到<string?1>結(jié)尾的字符數(shù),此函數(shù)將<string?1?>在<starting position-1>處截斷
---------------------------------------------------------------------------
FOR?XML PATH 語句的應用
大家都知道在SQL Server中利用?FOR?XML PATH 語句能夠把查詢的數(shù)據(jù)生成XML數(shù)據(jù),下面是它的一些應用示例。
DECLARE?@TempTable?table(UserID?int?, UserName?nvarchar(50));
insert?into?@TempTable?(UserID,UserName)?values?(1,'a')
insert?into?@TempTable?(UserID,UserName)?values?(2,'b')
select?UserID,UserName?from?@TempTable?FOR?XML PATH
運行這段腳本,將生成如下結(jié)果:
<row>
<UserID>1</UserID>
<UserName>a</UserName>
</row>
<row>
<UserID>2</UserID>
<UserName>b</UserName>
</row>
大家可以看到兩行數(shù)據(jù)生成了兩個節(jié)點,修改一下PATH的參數(shù):
select?UserID,UserName?from?@TempTable?FOR?XML PATH('lzy')
再次運行上述腳本,將生成如下的結(jié)果:
<lzy>
<UserID>1</UserID>
<UserName>a</UserName>
</lzy>
<lzy>
<UserID>2</UserID>
<UserName>b</UserName>
</lzy>
可以看到節(jié)點變成,其實PATH() 括號內(nèi)的參數(shù)是控制節(jié)點名稱的,這樣的話大家可以看一下如果是空字符串(不是沒有參數(shù))會是什么結(jié)果?
select?UserID,UserName?from?@TempTable?FOR?XML PATH('')
執(zhí)行上面這段腳本將生成結(jié)果:
<UserID>1</UserID>
<UserName>a</UserName>
<UserID>2</UserID>
<UserName>b</UserName>
這樣就不顯示上級節(jié)點了,大家知道在 PATH 模式中,列名或列別名被作為 XPath 表達式來處理,也就是說,是列的名字,這樣大膽試驗一下不給指定列名和別名會是怎么樣?
select?CAST(UserID?AS?varchar)?+?'',UserName?+?''?from?@TempTable?FOR?XML PATH('')
運行上面這句將生成結(jié)果
1a2b
所有數(shù)據(jù)都生成一行,而且還沒有連接字符,這樣的數(shù)據(jù)可能對大家沒有用處,還可以再變化一下:
select?CAST(UserID?AS?varchar)?+?',',UserName?+?'',';'?from?@TempTable?FOR?XML PATH('')
生成結(jié)果
1,a;2,b;
大家現(xiàn)在明白了吧,可以通過控制參數(shù)來生成自己想要的結(jié)果,例如:
select?'{'?+?CAST(UserID?AS?varchar)?+?',','"'?+UserName?+?'"','}'?from?@TempTable?FOR?XML PATH('')
生成結(jié)果
{1,"a"}{2,"b"}
還可以生成其他格式,大家可以根據(jù)自己需要的格式進行組合。
下面是一個數(shù)據(jù)統(tǒng)計的應用,希望大家可以通過下面的實例想到更多的應用
DECLARE?@T1?table(UserID?int?, UserName?nvarchar(50),CityName?nvarchar(50));
insert?into?@T1?(UserID,UserName,CityName)?values?(1,'a','上海')
insert?into?@T1?(UserID,UserName,CityName)?values?(2,'b','北京')
insert?into?@T1?(UserID,UserName,CityName)?values?(3,'c','上海')
insert?into?@T1?(UserID,UserName,CityName)?values?(4,'d','北京')
insert?into?@T1?(UserID,UserName,CityName)?values?(5,'e','上海')
SELECT?B.CityName,LEFT(UserList,LEN(UserList)-1)?FROM?(
SELECT?CityName,
(SELECT?UserName+','?FROM?@T1?WHERE?CityName=A.CityName?FOR?XML PATH(''))?AS?UserList
FROM?@T1?A?
GROUP?BY?CityName
) B
生成結(jié)果(每個城市的用戶名)
北京 b,d
上海 a,c,e
?
靈活運用 SQL SERVER FOR XML PATH
??????? FOR XML PATH 有的人可能知道有的人可能不知道,其實它就是將查詢結(jié)果集以XML形式展現(xiàn),有了它我們可以簡化我們的查詢語句實現(xiàn)一些以前可能需要借助函數(shù)活存儲過程來完成的工作。那么以一個實例為主.
????????一.FOR XML PATH 簡單介紹
?????????????那么還是首先來介紹一下FOR XML PATH ,假設現(xiàn)在有一張興趣愛好表(hobby)用來存放興趣愛好,表結(jié)構(gòu)如下:
???????接下來我們來看應用FOR XML PATH的查詢結(jié)果語句如下:
SELECT*FROM@hobbyFORXML?PATH?????? 結(jié)果:
<row>??<hobbyID>1</hobbyID>
??<hName>爬山</hName>
</row>
<row>
??<hobbyID>2</hobbyID>
??<hName>游泳</hName>
</row>
<row>
??<hobbyID>3</hobbyID>
??<hName>美食</hName>
</row>
????? 由此可見FOR XML PATH 可以將查詢結(jié)果根據(jù)行輸出成XML各式!
????? 那么,如何改變XML行節(jié)點的名稱呢?代碼如下:?????
SELECT*FROM@hobbyFORXML?PATH('MyHobby')?
????? 結(jié)果一定也可想而知了吧?沒錯原來的行節(jié)點<row> 變成了我們在PATH后面括號()中,自定義的名稱<MyHobby>,結(jié)果如下:
<MyHobby>??<hobbyID>1</hobbyID>
??<hName>爬山</hName>
</MyHobby>
<MyHobby>
??<hobbyID>2</hobbyID>
??<hName>游泳</hName>
</MyHobby>
<MyHobby>
??<hobbyID>3</hobbyID>
??<hName>美食</hName>
</MyHobby>
????? 這個時候細心的朋友一定又會問那么列節(jié)點如何改變呢?還記的給列起別名的關鍵字AS嗎?對了就是用它!代碼如下:
SELECThobbyID?as'MyCode',hName?as'MyName'FROM@hobbyFORXML?PATH('MyHobby')?
????? 那么這個時候我們列的節(jié)點名稱也會編程我們自定義的名稱 <MyCode>與<MyName>結(jié)果如下: <MyHobby>??<MyCode>1</MyCode>
??<MyName>爬山</MyName>
</MyHobby>
<MyHobby>
??<MyCode>2</MyCode>
??<MyName>游泳</MyName>
</MyHobby>
<MyHobby>
??<MyCode>3</MyCode>
??<MyName>美食</MyName>
</MyHobby> ??? 噢! 既然行的節(jié)點與列的節(jié)點我們都可以自定義,我們是否可以構(gòu)建我們喜歡的輸出方式呢?還是看代碼:? SELECT'[?'+hName+']'FROM@hobbyFORXML?PATH('')
??? 沒錯我們還可以通過符號+號,來對字符串類型字段的輸出格式進行定義。結(jié)果如下:
[?爬山?][?游泳?][?美食?]??? 那么其他類型的列怎么自定義? 沒關系,我們將它們轉(zhuǎn)換成字符串類型就行啦!例如:
SELECT'{'+STR(hobbyID)+'}','[?'+hName+']'FROM@hobbyFORXML?PATH('')??? 好的 FOR XML PATH就基本介紹到這里吧,更多關于FOR XML的知識請查閱幫助文檔!
??? 接下來我們來看一個FOR XML PATH的應用場景吧!那么開始吧。。。。。。
??????? 二.一個應用場景與FOR XML PATH應用
????????首先呢!我們在增加一張學生表,列分別為(stuID,sName,hobby),stuID代表學生編號,sName代表學生姓名,hobby列存學生的愛好!那么現(xiàn)在表結(jié)構(gòu)如下:
???????????
??????? 這時,我們的要求是查詢學生表,顯示所有學生的愛好的結(jié)果集,代碼如下:
SELECTB.sName,LEFT(StuList,LEN(StuList)-1)?ashobby?FROM(SELECTsName,
(SELECThobby+','FROMstudent?
??WHEREsName=A.sName?
??FORXML?PATH(''))?ASStuList
FROMstudent?A?
GROUPBYsName
)?B?
???????? 結(jié)果如下:
?分析:?好的,那么我們來分析一下,首先看這句:
SELECThobby+','FROMstudent???WHEREsName=A.sName?
??FORXML?PATH('')
這句是通過FOR XML PATH 將某一姓名如張三的愛好,顯示成格式為:“ 愛好1,愛好2,愛好3,”的格式!
那么接著看:
SELECTB.sName,LEFT(StuList,LEN(StuList)-1)?ashobby?FROM(SELECTsName,
(SELECThobby+','FROMstudent?
??WHEREsName=A.sName?
??FORXML?PATH(''))?ASStuList
FROMstudent?A?
GROUPBYsName
)?B??
剩下的代碼首先是將表分組,在執(zhí)行FOR XML PATH 格式化,這時當還沒有執(zhí)行最外層的SELECT時查詢出的結(jié)構(gòu)為:
可以看到StuList列里面的數(shù)據(jù)都會多出一個逗號,這時隨外層的語句:SELECT?B.sName,LEFT(StuList,LEN(StuList)-1)?as?hobby??就是來去掉逗號,并賦予有意義的列明!
好啦,太晚啦就說到這里吧!
?
?
?
?
?
?
轉(zhuǎn)載于:https://www.cnblogs.com/dabaopku/archive/2012/07/18/2597237.html
總結(jié)
以上是生活随笔為你收集整理的使用 FOR XML PATH 合并SQL Server查询结果的重复行的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 以简求快--java快速开发框架
- 下一篇: Android帧缓冲区(Frame Bu