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