Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

O que essa consulta faz para criar uma lista delimitada por vírgulas no SQL Server?


A maneira mais simples de explicar é ver como FOR XML PATH funciona para XML real. Imagine uma tabela simples Employee :
EmployeeID      Name
1               John Smith
2               Jane Doe

Você poderia usar
SELECT  EmployeeID, Name
FROM    emp.Employee
FOR XML PATH ('Employee')

Isso criaria XML da seguinte forma
<Employee>
    <EmployeeID>1</EmployeeID>
    <Name>John Smith</Name>
</Employee>
<Employee>
    <EmployeeID>2</EmployeeID>
    <Name>Jane Doe</Name>
</Employee>

Removendo o 'Employee' de PATH remove as tags xml externas para que esta consulta:
SELECT  Name
FROM    Employee
FOR XML PATH ('')

Criaria
    <Name>John Smith</Name>
    <Name>Jane Doe</Name>

O que você está fazendo então não é o ideal, o nome da coluna 'data()' força um erro de sql porque está tentando criar uma tag xml que não é uma tag legal, então o seguinte erro é gerado:

O nome da coluna 'Data()' contém um identificador XML inválido conforme exigido por FOR XML; '('(0x0028) é o primeiro caractere com falha.

A subconsulta correlacionada oculta esse erro e apenas gera o XML sem tags:
SELECT  Name AS [Data()]
FROM    Employee
FOR XML PATH ('')

cria
John Smith Jane Doe

Você está então substituindo espaços por vírgulas, bastante auto-explicativos ...

Se eu fosse você, adaptaria um pouco a consulta:
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; 

Não ter nenhum alias de coluna significa que nenhuma tag xml é criada, e adicionar a vírgula na consulta de seleção significa que quaisquer nomes com espaços não causarão erros, STUFF irá remover a primeira vírgula e espaço.

ADENDO

Para elaborar sobre o que KM disse em um comentário, como isso parece estar recebendo mais algumas visualizações, a maneira correta de escapar caracteres XML seria usar .value do seguinte modo:
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;