sql >> Base de Datos >  >> RDS >> Sqlserver

¿Qué hace esta consulta para crear una lista delimitada por comas en SQL Server?

La forma más sencilla de explicarlo es ver cómo FOR XML PATH funciona para XML real. Imagina una tabla simple Employee :

EmployeeID      Name
1               John Smith
2               Jane Doe

Podrías usar

SELECT  EmployeeID, Name
FROM    emp.Employee
FOR XML PATH ('Employee')

Esto crearía XML de la siguiente manera

<Employee>
    <EmployeeID>1</EmployeeID>
    <Name>John Smith</Name>
</Employee>
<Employee>
    <EmployeeID>2</EmployeeID>
    <Name>Jane Doe</Name>
</Employee>

Eliminando el 'Empleado' de PATH elimina las etiquetas xml externas, por lo que esta consulta:

SELECT  Name
FROM    Employee
FOR XML PATH ('')

Crearía

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

Lo que está haciendo entonces no es ideal, el nombre de la columna 'data()' fuerza un error de sql porque está tratando de crear una etiqueta xml que no es una etiqueta legal, por lo que se genera el siguiente error:

El nombre de columna 'Data()' contiene un identificador XML no válido según lo requiere FOR XML; '('(0x0028) es el primer carácter que falla.

La subconsulta correlacionada oculta este error y solo genera el XML sin etiquetas:

SELECT  Name AS [Data()]
FROM    Employee
FOR XML PATH ('')

crea

John Smith Jane Doe

Luego está reemplazando espacios con comas, bastante explicativo...

Si yo fuera usted, adaptaría ligeramente la 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; 

No tener un alias de columna significará que no se crearán etiquetas xml, y agregar la coma dentro de la consulta de selección significa que cualquier nombre con espacios no causará errores, STUFF eliminará la primera coma y el espacio.

ANEXO

Para profundizar en lo que KM ha dicho en un comentario, ya que parece que esto está recibiendo algunas visitas más, la forma correcta de escapar de los caracteres XML sería usar .value de la siguiente manera:

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;