此查询如何创建逗号分隔的SQL Server列表?
我在google的帮助下编写了这个查询,从一个表中创建了一个带分隔符的列表,但我不理解这个查询中的任何内容 谁能解释一下发生了什么事此查询如何创建逗号分隔的SQL Server列表?,sql,sql-server,sql-server-2008,Sql,Sql Server,Sql Server 2008,我在google的帮助下编写了这个查询,从一个表中创建了一个带分隔符的列表,但我不理解这个查询中的任何内容 谁能解释一下发生了什么事 SELECT E1.deptno, allemp = Replace ((SELECT E2.ename AS 'data()' FROM emp AS e2 WHERE e1.deptno = e2.DEPTNO
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
外部查询检索部门编号列表,然后对每个部门编号运行子查询,以返回属于该部门的所有名称。子查询使用FOR XML语句将输出格式化为一行逗号分隔的列表。将其从内到外逐步分解 第1步: 运行最内部的查询并查看其生成的内容:
SELECT E2.ename AS 'data()'
FROM emp AS e2
WHERE e2.DEPTNO = 10
FOR XML PATH('')
您应该得到如下输出:
CLARK KING MILLER
第二步:
REPLACE
仅将空格替换为,
——从而将输出转换为
CLARK, KING, MILLER
第三步:
外部查询获取
deptno
值,加上内部查询的结果,并生成最终结果。解释它的最简单方法是查看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>
会创造
<Name>John Smith</Name>
<Name>Jane Doe</Name>
创造
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;
SQL Server 2017使这一过程变得更加简单。最近我看到了这篇文章,将我的STUFF/FOR XML策略改为使用新的字符串函数。还避免了额外的连接/子查询,避免了XML的开销(以及奇怪的编码问题)和难以解释的SQL
SELECT E1.deptno,
STRING_AGG(E1.ename, ', ') AS allemp
FROM EMP AS e1
GROUP BY DEPTNO;
注意:还要确保更轻松地使用SQL分隔的数据 请注意,对于包含字符的文本,您的代码将失败,如><&您将获得字符扩展,如
,&
有一种更好的方法来实现这种连接,请参见:+1良好的解释,但请注意,对于包含字符的文本,此代码将失败,如><&您将获得字符扩展,如
,&
有一种更好的方法来实现这种连接,请参见:您缺少一个引号来结束'NVARCHAR(MAX)
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;
SELECT E1.deptno,
STRING_AGG(E1.ename, ', ') AS allemp
FROM EMP AS e1
GROUP BY DEPTNO;