我在google的帮助下编写了这个查询,从表中创建了一个分隔列表,但我对此查询没有任何理解。
任何人都可以解释我发生了什么
SELECT
E1.deptno,
allemp = Replace ((SELECT E2.ename AS 'data()'
FROM emp AS e2
WHERE e1.deptno = e2.DEPTNO
FOR xml PATH('')), ' ', ', ')
FROM EMP AS e1
GROUP BY DEPTNO;
给我结果
10 CLARK, KING, MILLER
20 SMITH, JONES, SCOTT, ADAMS, FORD
30 ALLEN, WARD, MARTIN, BLAKE, TURNER, JAMES
答案 0 :(得分:36)
解释它的最简单方法是查看FOR XML PATH
如何为实际XML工作。想象一个简单的表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
将删除第一个逗号和空格。
<强>附录强>
要详细说明知识管理在评论中所说的内容,因为这似乎可以获得更多视图,转义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;
答案 1 :(得分:6)
从内到外逐步分开。
第1步:
运行最里面的查询并查看它产生的内容:
SELECT E2.ename AS 'data()'
FROM emp AS e2
WHERE e2.DEPTNO = 10
FOR XML PATH('')
你应该得到类似的输出:
CLARK KING MILLER
第2步:
REPLACE
只是用,
替换空格 - 从而将输出转换为
CLARK, KING, MILLER
第3步:
外部查询获取deptno
值 - 加上内部查询的结果 - 并生成最终结果。
答案 2 :(得分:1)
SQL Server 2017 使new STRING_AGG
更容易。最近发现这篇文章并切换我的 STUFF / FOR XML 策略以使用新的字符串函数。还避免了需要额外的JOIN / SUBQUERY以及FOR XML(和奇数编码问题)的开销,并且难以解释SQL。
SELECT E1.deptno,
STRING_AGG(E1.ename, ', ') AS allemp
FROM EMP AS e1
GROUP BY DEPTNO;
注意:还要确保check out the counterpart STRING_SPLIT
更容易使用SQL分隔数据。
答案 3 :(得分:0)
外部查询检索部门编号列表,然后为每个部门编号运行子查询以返回属于该部门的所有名称。子查询使用FOR XML语句将输出格式化为单行逗号分隔列表。