SQL Server中有提供一個FOR XML PATH的子句(不知道能不能叫函數),用來將查詢結果行輸出成XML格式,我們可以通過這個語法做一些變通實現一些特定的功能,比如說行轉列。要會變通的話,當然首先是要知道FOR XML PATH的語法。
FOR XML PATH的簡單語法
假設有一個hobby表(愛好),表中有兩個字段,一個是hobbyID(愛好id),一個是hName(愛好名稱)。
這樣,我們執行一條最簡單的帶FOR XML PATH子句的SQL語句,看看查詢出來的結果。
SELECT * FROM hobby FOR XML 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格式。
FOR XML PATH的變通
更多的,FOR XML PATH子句是支持傳遞參數的,即FOR XML PATH(schema),這樣的話在查詢的時候就會將行標簽<row>替換為<schema>,要注意的是schema必須是字符串。
SELECT * FROM hobby FOR XML PATH('yanggb');
<yanggb> <hobbyID>1</hobbyID> <hName>爬山</hName> </yanggb> <yanggb> <hobbyID>2</hobbyID> <hName>游泳</hName> </yanggb> <yanggb> <hobbyID>3</hobbyID> <hName>美食</hName> </yanggb>
這時候,就可以利用XML的特點,即空標簽不會存在的特定,將行標簽<row>去掉。
SELECT * FROM hobby FOR XML PATH('');
<hobbyID>1</hobbyID> <hName>爬山</hName> <hobbyID>2</hobbyID> <hName>游泳</hName> <hobbyID>3</hobbyID> <hName>美食</hName>
那能更改/去除行標簽<row>,能不能更改/去除列標簽呢?答案是可以的,可以通過給列起別名的方式來更改/除列標簽。要注意的是這里的別名也必須是字符串。
SELECT hobbID AS AA, hName AS BB FROM hobby FOR XML PATH('');
<AA>1</AA> <BB>爬山</BB> <AA>2</AA> <BB>游泳</BB> <AA>3</AA> <BB>美食</BB>
與去除行標簽<row>的方式不一樣的是,去除列標簽不能將別名定義為空字符串,否則數據庫引擎會報錯誤:[Err] 42000 - [SQL Server]缺少對象或列名,或者對象或列名為空。對於 SELECT INTO 語句,請確保每列均具有名稱。對於其他語句,請查找空的別名。不允許使用定義為 "" 或 [] 的別名。請將別名更改為有效名稱。
那么要怎么去除列標簽呢,做法是給字段加上空字符串(加任何字符串都可以,我的理解是這種做法修改了列值,在沒有起別名的情況下,原來的列標簽不再匹配列值,數據庫引擎會將自動該列標簽去除)。
SELECT hobbID + '', hName + '' FROM hobby FOR XML PATH('');
1爬山2游泳3美食
FOR XML PATH實現行轉列
根據上面的FOR XML PATH的變通的內容,我們就可以來實現行轉列了。
SELECT hName, (SELECT ',' + hName FROM hobby FOR XML PATH('')) AS hNames FROM hobby FOR XML PATH('');
這樣我們就能得到一個所有愛好拼接起來的列hNames。
這時候我們會發現hNames字段值多了一個逗號,使用STUFF函數(推薦)或REPLACE函數去除即可。
更多的,可以在FOR XML PATH子句前添加WHERE子句限定條件范圍來限定行轉列的范圍(也可以使用自連接限定當前行轉列的范圍)。
當然了,SQL SERVER還提供了另外的行轉列的PRIVOT函數和列轉行的UNPRIVOT函數。
"一個姑娘不會因為你專一痴情就喜歡你,只會因為你優秀而喜歡你。"