昨天遇到一個SQL Server的問題:需要寫一個儲存過程來處理幾個表中的數據,最后問題出在我想將一個表的一個列的多行內容拼接成一行
比如表中有兩列數據 :
ep_classes ep_name
AAA 企業1
AAA 企業2
AAA 企業3
BBB 企業4
BBB 企業5
我想把這個表變成如下格式:
ep_classes ep_name
AAA 企業1,企業2,企業3
BBB 企業4,企業5
原先的表名為:ep_detail。
實現代碼如下:
select ep_classes, ep_name = (stuff((select ‘,’ + ep_name from ep_detail where ep_classes = a.ep_classes for xml path(”)),1,1,”)) from ep_detail a group by ep_classes
這里使用了SQL Server 2005版本以后加入的stuff以及for xml path,先說下在上面這句sql中的作用,然后再詳細的說明一下這兩個的用法。
for xml path(”)
這句是把得到的內容以XML的形式顯示。
stuff((select ‘,’ + ep_name from ep_detail where ep_classes = a.ep_classes for xml path(”)),1,1,”)
這句是把拼接的內容的第一個“,”去掉
好了,現在開始具體說一下用法:
①stuff:
1、作用
stuff(param1, startIndex, length, param2)
將param1中自startIndex(SQL中都是從1開始,而非0)起,刪除length個字符,然后用param2替換刪掉的字符。
2、參數
param1
一個字符數據表達式。param1可以是常量、變量,也可以是字符列或二進制數據列。
startIndex
一個整數值,指定刪除和插入的開始位置。如果 startIndex或 length 為負,則返回空字符串。如果startIndex比param1長,則返回空字符串。startIndex可以是 bigint 類型。
length
一個整數,指定要刪除的字符數。如果 length 比param1長,則最多刪除到param1 中的最后一個字符。length 可以是 bigint 類型。
3、返回類型
如果param1是受支持的字符數據類型,則返回字符數據。如果param1是一個受支持的 binary 數據類型,則返回二進制數據。
4、備注
如果結果值大於返回類型支持的最大值,則產生錯誤。
eg:
select STUFF(‘abcdefg’,1,0,‘1234’) –結果為’1234abcdefg’ select STUFF(‘abcdefg’,1,1,‘1234’) –結果為’1234bcdefg’ select STUFF(‘abcdefg’,2,1,‘1234’) –結果為’a1234cdefg’ select STUFF(‘abcdefg’,2,2,‘1234’) –結果為’a1234defg’
通過以上4個小例子,應該能明白stuff的用法了。
②for xml path:
for xml path有的人可能知道有的人可能不知道,其實它就是將查詢結果集以XML形式展現,有了它我們可以簡化我們的查詢語句實現一些以前可能需要借助函數活存儲過程來完成的工作。那么以一個實例為主.
我們還是通過列子引入:
假設有個表存放着學生的選課情況(stu_courses):
接下來我們來看應用FOR XML PATH的查詢結果語句如下:
select stu_name,stu_course from stu_courses for xml path;
結果如下:
<row> <stu_name>張三</stu_name> <stu_course>數學</stu_course> </row> <row> <stu_name>張三</stu_name> <stu_course>語文</stu_course> </row> <row> <stu_name>張三</stu_name> <stu_course>英語</stu_course> </row> <row> <stu_name>李四</stu_name> <stu_course>數學</stu_course> </row> <row> <stu_name>李四</stu_name> <stu_course>語文</stu_course> </row>
由此可以看出 FOR XML PATH 可以將查詢結果根據行輸出成XML各式!而且我們還可以改變XML行節點的名稱,代碼如下:
select stu_name,stu_course from stu_courses for xml path(‘course’);
看顯示結果,原來的行節點<row> 變成了我們在PATH后面括號()中自定義的名稱<course>:
<course> <stu_name>張三</stu_name> <stu_course>數學</stu_course> </course> <course> <stu_name>張三</stu_name> <stu_course>語文</stu_course> </course> <course> <stu_name>張三</stu_name> <stu_course>英語</stu_course> </course> <course> <stu_name>李四</stu_name> <stu_course>數學</stu_course> </course> <course> <stu_name>李四</stu_name> <stu_course>語文</stu_course> </course>
其實我們還可以改變列節點,還記的給列起別名的關鍵字AS嗎?就是用它!代碼如下:
select stu_name as MyName,stu_course as MyCourse from stu_courses for xml path(‘course’);
<course> <MyName>張三</MyName> <MyCourse>數學</MyCourse> </course> <course> <MyName>張三</MyName> <MyCourse>語文</MyCourse> </course> <course> <MyName>張三</MyName> <MyCourse>英語</MyCourse> </course> <course> <MyName>李四</MyName> <MyCourse>數學</MyCourse> </course> <course> <MyName>李四</MyName> <MyCourse>語文</MyCourse> </course>
我們還可以構建我們喜歡的輸出方式,看代碼:
select ‘[‘+stu_name+‘,’+stu_course+‘]’ from stu_courses for xml path(”);
顯示結果:
[張三,數學][張三,語文][張三,英語][李四,數學][李四,語文]
好了,通過上面的說明,估計大家就可以明白開始問題中的sql語句了!
當然,關於開始的問題還有其他的解決辦法,比如:游標、自定義函數等等,那些以后再做補充吧。
以上僅作拋磚引玉之用,如果有問題或者其他的簡便方法,希望提出大家共同討論學習!