这个查询创建逗号分隔列表SQL Server的作用是什么?

Reg*_*ser 12 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 
                       FOR xml PATH('')), ' ', ', ') 
 FROM EMP AS e1 
 GROUP BY DEPTNO; 
Run Code Online (Sandbox Code Playgroud)

给我结果

10  CLARK, KING, MILLER
20  SMITH, JONES, SCOTT, ADAMS, FORD
30  ALLEN, WARD, MARTIN, BLAKE, TURNER, JAMES
Run Code Online (Sandbox Code Playgroud)

Gar*_*thD 38

解释它的最简单方法是查看FOR XML PATH实际XML的工作原理.想象一个简单的表格Employee:

EmployeeID      Name
1               John Smith
2               Jane Doe
Run Code Online (Sandbox Code Playgroud)

你可以用

SELECT  EmployeeID, Name
FROM    emp.Employee
FOR XML PATH ('Employee')
Run Code Online (Sandbox Code Playgroud)

这将创建XML如下

<Employee>
    <EmployeeID>1</EmployeeID>
    <Name>John Smith</Name>
</Employee>
<Employee>
    <EmployeeID>2</EmployeeID>
    <Name>Jane Doe</Name>
</Employee>
Run Code Online (Sandbox Code Playgroud)

删除'Employee' PATH会删除外部xml标记,因此此查询:

SELECT  Name
FROM    Employee
FOR XML PATH ('')
Run Code Online (Sandbox Code Playgroud)

会创造

    <Name>John Smith</Name>
    <Name>Jane Doe</Name>
Run Code Online (Sandbox Code Playgroud)

您正在做的事情并不理想,列名'data()'强制sql错误,因为它试图创建一个不合法标记的xml标记,因此会生成以下错误:

列名'Data()'包含FOR XML所需的无效XML标识符; '('(0x0028)是第一个出错的角色.

相关子查询隐藏此错误,只生成没有标记的XML:

SELECT  Name AS [Data()]
FROM    Employee
FOR XML PATH ('')
Run Code Online (Sandbox Code Playgroud)

创建

John Smith Jane Doe
Run Code Online (Sandbox Code Playgroud)

然后你用逗号替换空格,相当自我解释......

如果我是你,我会略微调整查询:

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; 
Run Code Online (Sandbox Code Playgroud)

没有列别名将意味着没有创建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; 
Run Code Online (Sandbox Code Playgroud)

  • +1一个很好的解释,但请注意这个代码将失败包含字符的文字> <&**你会得到字符扩展,如`&lt;`,`&gt;``&amp;`有一个更好的方法这个串联,请参阅:http://stackoverflow.com/a/5031297/65223 (4认同)

mar*_*c_s 6

从内到外逐步分开.

步骤1:

运行最里面的查询并查看它产生的内容:

SELECT E2.ename AS 'data()' 
FROM emp AS e2 
WHERE e2.DEPTNO = 10
FOR XML PATH('')
Run Code Online (Sandbox Code Playgroud)

你应该得到一个类似的输出:

CLARK KING MILLER
Run Code Online (Sandbox Code Playgroud)

第2步:

REPLACE刚刚替换空间与,-从而把您的输出入

CLARK, KING, MILLER
Run Code Online (Sandbox Code Playgroud)

第3步:

外部查询获取deptno值 - 加上内部查询的结果 - 并生成最终结果.