最简单的解释方法是看看如何在实际的XML中使用FOR XML PATH
。想象一个简单的表Employee
:
EmployeeID Name
1 John Smith
2 Jane Doe
你可以使用
SELECT EmployeeID, Name
FROM emp.Employee
FOR XML PATH ('Employee')
这将创建以下 XML
<Employee>
<EmployeeID>1</EmployeeID>
<Name>John Smith</Name>
</Employee>
<Employee>
<EmployeeID>2</EmployeeID>
<Name>Jane Doe</Name>
</Employee>
从 PATH
中删除 'Employee' 将移除外部 XML 标记,因此该查询语句为:
SELECT Name
FROM Employee
FOR XML PATH ('')
将会创建
<Name>John Smith</Name>
<Name>Jane Doe</Name>
你所做的不是最理想的方式,列名“data()”会导致SQL出错,因为它尝试创建一个非法标签的XML标记,因此会生成以下错误:
列名'Data()'包含FOR XML所需的无效XML标识符;'('(0x0028)是第一个有问题的字符。
相关子查询隐藏了此错误并只生成没有标记的XML:
SELECT Name AS [Data()]
FROM Employee
FOR XML PATH ('')
创建
John Smith Jane Doe
你将空格替换为逗号,这很容易理解...
如果我是你,我会稍微改写查询:
SELECT E1.deptno,
STUFF(( SELECT ', ' + E2.ename
FROM emp AS e2
WHERE e1.deptno = e2.DEPTNO
FOR XML PATH('')
), 1, 2, '')
FROM EMP AS e1
GROUP BY DEPTNO;
如果没有列别名,则不会创建任何xml标签,将逗号添加到select查询中意味着名称中带有空格的任何名称都不会导致错误,STUFF
将删除第一个逗号和空格。
补充说明
为了阐明KM在评论中所说的内容,因为这似乎吸引了更多的关注,正确转义XML字符的方法是使用.value
,如下所示:
SELECT E1.deptno,
STUFF(( SELECT ', ' + E2.ename
FROM emp AS e2
WHERE e1.deptno = e2.DEPTNO
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)'), 1, 2, '')
FROM EMP AS e1
GROUP BY DEPTNO;
<
,>
和&
。有一种更好的方法来进行连接,请参阅:https://dev59.com/Q2445IYBdhLWcg3wH2rH#5031297 - KM.