SQL——用FOR XML Path完成字串的聚合

iteye_20954發表於2012-01-03
CREATE TABLE #Temp(GroupName VARCHAR(100),FuncationName VARCHAR(100)) GO INSERT INTO #Temp VALUES('Administrator','View') INSERT INTO #Temp VALUES('Administrator','Add') INSERT INTO #Temp VALUES('Administrator','Delete') INSERT INTO #Temp VALUES('Administrator','Edit') INSERT INTO #Temp VALUES('Guest','View') INSERT INTO #Temp VALUES('Guest','Add') INSERT INTO #Temp VALUES('GG','View') INSERT INTO #Temp VALUES('Test',NULL) SELECT FuncationName+',' FROM #Temp FOR XML PATH('') -- View,Add,Delete,Edit,View,Add,View, SELECT isnull(FuncationName,'')+',' FROM #Temp FOR XML PATH('') -- View,Add,Delete,Edit,View,Add,View,, SELECT FuncationName+',' FROM #Temp WHERE GroupName='Administrator' FOR XML PATH('') -- View,Add,Delete,Edit, SELECT GroupName, ( SELECT FuncationName+',' FROM #Temp AS TA WHERE TA.GroupName=TB.GroupName FOR XML PATH('') ) FROM #Temp TB GROUP BY GroupName --Administrator View,Add,Delete,Edit, --GG View, --Guest View,Add, --Test --注:這一步操作一定要用 case 判斷, 因為在null值的情況下left函式會出錯。 SELECT t.GroupName,CASE LEN(t.FunList) WHEN 0 THEN '' ELSE LEFT(t.FunList,len(t.FunList)-1) END FROM ( SELECT GroupName, ( SELECT FuncationName+',' FROM #Temp AS TA WHERE TA.GroupName=TB.GroupName FOR XML PATH('') ) AS FunList FROM #Temp TB GROUP BY GroupName ) AS T --Administrator View,Add,Delete,Edit --GG View --Guest View,Add --Test --注:這一步,逗號必須放在最前面,stuff函式只有放在最前面才能準確判斷 --此外,與上面不同的是,它會自動過濾掉NULL值的情況,不作處理 Select TB.GroupName, stuff((select ','+[FuncationName] from #Temp AS TA WHERE TA.GroupName=TB.GroupName for xml path('')),1,1,'') AS FunList from #Temp TB GROUP BY TB.GroupName --Administrator View,Add,Delete,Edit --GG View --Guest View,Add --Test NULL


下面是轉載別人的。

——————————————————————————————————————————————

在SQL Server中利用 FOR XML PATH 語句能夠把查詢的資料生成XML資料,下面是它的一些應用示例。

1
2
3
4
5
DECLARE @TempTable table(UserIDint, 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
執行這段指令碼,將生成如下結果:
1
2
3
4
5
6
7
8
<row>
<UserID>1</UserID>
<UserName>a</UserName>
</row>
<row>
<UserID>2</UserID>
<UserName>b</UserName>
</row>
1
大家可以看到兩行資料生成了兩個節點,修改一下PATH的引數:
1
select UserID,UserName from @TempTable FOR XML PATH('lzy')

再次執行上述指令碼,將生成如下的結果:

1
2
3
4
5
6
7
8
<lzy>
<UserID>1</UserID>
<UserName>a</UserName>
</lzy>
<lzy>
<UserID>2</UserID>
<UserName>b</UserName>
</lzy>
1
可以看到節點變成,其實PATH() 括號內的引數是控制節點名稱的,這樣的話大家可以看一下如果是空字串(不是沒有引數)會是什麼結果?
1
select UserID,UserName from @TempTable FOR XML PATH('')

執行上面這段指令碼將生成結果:

1
2
3
4
<UserID>1</UserID>
<UserName>a</UserName>
<UserID>2</UserID>
<UserName>b</UserName>

這樣就不顯示上級節點了,大家知道在 PATH 模式中,列名或列別名被作為 XPath 表示式來處理,也就是說,是列的名字,這樣大膽試驗一下不給指定列名和別名會是怎麼樣?

1
select CAST(UserID ASvarchar) +'',UserName +''from@TempTable FORXML PATH('')

執行上面這句將生成結果

1a2b

所有資料都生成一行,而且還沒有連線字元,這樣的資料可能對大家沒有用處,還可以再變化一下:

1
select CAST(UserID ASvarchar) +',',UserName +'',';'from@TempTableFORXML PATH('')

生成結果

1,a;2,b;

大家現在明白了吧,可以通過控制引數來生成自己想要的結果,例如:

1
select '{' + CAST(UserIDASvarchar) +',','"'+UserName +'"','}'from@TempTableFORXML PATH('')

生成結果

{1,"a"}{2,"b"}

還可以生成其他格式,大家可以根據自己需要的格式進行組合。

下面是一個資料統計的應用,希望大家可以通過下面的例項想到更多的應用

1
2
3
4
5
6
7
8
9
10
11
12
13
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,
(SELECTUserName+','FROM@T1 WHERECityName=A.CityNameFORXML PATH(''))ASUserList
FROM @T1 A
GROUP BY CityName
) B

生成結果(每個城市的使用者名稱)

北京 b,d
上海 a,c,e

————————————————————————————————————————————————————————————

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嗎?對了就是用它!程式碼如下:

SELECThobbyIDas'MyCode',hNameas'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)ashobbyFROM(
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)ashobbyFROM(
SELECTsName,
(
SELECThobby+','FROMstudent
WHEREsName=A.sName
FORXML PATH(''))ASStuList
FROMstudent A
GROUPBYsName
) B

剩下的程式碼首先是將表分組,在執行FOR XML PATH 格式化,這時當還沒有執行最外層的SELECT時查詢出的結構為:

可以看到StuList列裡面的資料都會多出一個逗號,這時隨外層的語句:SELECTB.sName,LEFT(StuList,LEN(StuList)-1)ashobby就是來去掉逗號,並賦予有意義的列名!


相關文章