FOR XML PATH 是 SQL Server 將查詢結果序列化為 XML 的強大工具,更因其靈活的節點控制能力,成為 **字串聚合(行轉逗號分隔字串)** 的事實標準寫法。本文從基礎 XML 產生、節點自訂,深入到實戰「學生-愛好」一對多彙總場景。
DECLARE @hobby TABLE (hobbyID INT, hName NVARCHAR(20));
INSERT @hobby VALUES (1,N'爬山'),(2,N'游泳'),(3,N'美食');
-- 1. 預設 元素,欄位為屬性
SELECT * FROM @hobby FOR XML PATH;
SELECT * FROM @hobby FOR XML PATH('MyHobby');
SELECT hobbyID AS 'MyCode', hName AS 'MyName'
FROM @hobby FOR XML PATH('MyHobby');
1
爬山
...
AS 'Name' 可保留大小寫與特殊字元。@:hobbyID AS '@MyCode'。
SELECT * FROM @hobby FOR XML PATH('MyHobby'), ELEMENTS;
SELECT * FROM @hobby FOR XML PATH('MyHobby'), ROOT('HobbyList');
...
INSERT @hobby VALUES (4, NULL);
SELECT * FROM @hobby FOR XML PATH('MyHobby'), ELEMENTS XSINIL;
4
-- 輸出:[ 爬山 ][ 游泳 ][ 美食 ]
SELECT '[ ' + hName + ' ]' FROM @hobby FOR XML PATH('');
-- 輸出:{1}[ 爬山 ]{2}[ 游泳 ]{3}[ 美食 ]
SELECT '{' + CAST(hobbyID AS VARCHAR(10)) + '}[ ' + hName + ' ]'
FROM @hobby FOR XML PATH('');
PATH('') 移除行元素,直接輸出字串內容。CAST/CONVERT/STR 轉型。
DECLARE @student TABLE (stuID INT, sName NVARCHAR(10), hobby NVARCHAR(20));
INSERT @student VALUES
(1,N'張三',N'爬山'),(1,N'張三',N'游泳'),
(2,N'李四',N'美食'),(2,N'李四',N'閱讀'),(2,N'李四',N'程式');
SELECT
B.sName,
LEFT(StuList, LEN(StuList) - 1) AS hobby -- 移除尾隨逗號
FROM (
SELECT
sName,
(SELECT hobby + ',' FROM @student WHERE sName = A.sName FOR XML PATH('')) AS StuList
FROM @student A
GROUP BY sName
) B;
GROUP BY sName 取得不重複學生清單。SELECT hobby + ',' ... FOR XML PATH('') 將該生所有愛好串成 爬山,游泳,。LEFT(..., LEN()-1) 切掉最後一個逗號。
sName hobby
張三 爬山,游泳
李四 美食,閱讀,程式
SELECT sName, STRING_AGG(hobby, ',') AS hobby
FROM @student
GROUP BY sName;
WITHIN GROUP (ORDER BY ...) 排序。FOR XML PATH 技巧。| 議題 | 建議 |
|---|---|
| 大量資料聚合 | 子查詢相關子查詢可能產生 N+1 問題;大表建議先彙總到暫存表/表變數,再套用 FOR XML PATH。 |
| 特殊字元逸出 | XML 會自動編碼 & < >;若不想編碼需用 TYPE 指令搭配 .value() 提取,或改用 STRING_AGG。 |
| NULL 值 | 字串串接遇 NULL 會導致整串變 NULL;建議 ISNULL(hobby,'') 或 COALESCE。 |
| 排序保證 | 子查詢加 ORDER BY 確保聚合順序:SELECT hobby + ',' FROM ... ORDER BY hobby FOR XML PATH('')。 |
<row .../>,屬性化,適合簡單匯出。