在SQL Server里,把一张表的多行数据转换成一段连续的XML字符串,最常用的办法就是SELECT配合FOR XML PATH。它能把结果集的每一行映射为XML中的节点,再按照你给定的路径名称组织元素或属性。这种写法比手动拼字符串更安全,也能避免注入和编码问题。

基本语法与单行转节点的规则
FOR XML PATH的核心是在查询末尾加上FOR XML PATH('节点名'),其中节点名会成为每一行数据外层包裹的元素。如果不写节点名或写成空串PATH(''),SQL Server就不会添加额外的行容器,只把列直接转成子元素。例如有一张表存放部门员工,我们想为每个部门生成一个员工列表,就可以在子查询里用PATH把员工姓名拼起来。
当列名本身就是元素名时,PATH会默认用列名作标签。如果你用别名,比如SELECT Name AS Emp,那输出就是<Emp>张三</Emp>。若希望某列作为属性而非子元素,可以在列名前加@,如SELECT Name AS [@Emp],这样会生成<row Emp="张三"/>。理解这套映射逻辑,是控制输出形状的第一步。
下面这段示例展示最基础的用法:把产品表中的名称和价格转成带行容器的XML。
SELECT
ProductName AS Name,
Price AS Price
FROM Products
WHERE CategoryID = 1
FOR XML PATH('Product'), ROOT('Products');
上面的查询会返回类似<Products><Product><Name>笔</Name><Price>3.5</Price></Product>...</Products>的结果。ROOT用于包裹所有行,避免顶层多个节点不合法。掌握了这个结构,就能在此之上做更灵活的拼接。
利用空PATH实现字符串拼接与自定义格式
很多场景并不需要严格XML,而是想把多行某列的值用逗号或分号连成一行文本。此时把PATH设为空串,并在SELECT里用常量文本配合列值,就能直接拼出纯文本或类XML片段。比如把订单里的商品名拼成用逗号分隔的串,可以写成SELECT ',' + ProductName FROM ... FOR XML PATH(''),再用STUFF去掉首位逗号。
这种写法比循环或变量累加高效,因为它是集合操作。但要注意,FOR XML PATH('')默认会对特殊字符转义,例如&、<会被变成实体。如果确认数据不含标记且要原样输出,可以加TYPE再取value,或者用text()指定文本节点减少嵌套。下面例子演示去首位逗号的标准做法。
SELECT STUFF(
(SELECT ',' + ProductName
FROM Products
WHERE CategoryID = 1
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')
, 1, 1, '') AS ProductList;
这里TYPE让内部结果是XML类型,.value('.', 'NVARCHAR(MAX)')把它转回字符串并保留原始字符,不会被二次转义。相比不用TYPE直接隐式转换,这种方式在处理含尖括号的产品名时更稳。实际开发中,报表字段合并、标签云生成都常用这个模式。
处理特殊字符、空值与嵌套查询
当数据里出现<、>、&等字符,FOR XML PATH会自动转为XML实体,保证结果良构。但如果后续要把这段XML当普通文本存到别的系统,可能需再解码。相反,若用text()方式输出,可以避免生成子元素而只留文本,减少节点噪音。对于NULL值,对应元素不会生成,若想保留占位,可以用ISNULL(col, '')先处理。
嵌套查询是另一个重点。主查询按分组字段聚合,子查询用PATH把组内多行拼成一段,就能实现“一行一分组、组内多值成串”的典型报表需求。如下面按客户汇总订单商品:
SELECT
CustomerID,
(SELECT ProductName AS Item
FROM Orders o2
WHERE o2.CustomerID = c.CustomerID
FOR XML PATH(''), ROOT('Items'), TYPE)
FROM Customers c
FOR XML PATH('Customer'), ROOT('Customers');
这段会为每个客户生成一个<Items>块,里面是多个<Item>。由于外层也用了PATH,整体就是分层XML。如果不要ROOT,内层就是纯片段,方便和其他系统对接。空值方面,若某客户无订单,子查询返回空,可用ISNULL(... , '<Items/>')在外层包一层判断。理解这些细节后,你就能用FOR XML PATH稳定地把任意查询结果拼成所需XML或文本。
SQL_ServerFOR_XML_PATHXML拼接修改时间:2026-08-16 22:32:29