Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Che cosa fa questa query per creare un elenco delimitato da virgole SQL Server?

Il modo più semplice per spiegarlo è guardare come FOR XML PATH funziona per l'XML effettivo. Immagina una semplice tabella Employee :

EmployeeID      Name
1               John Smith
2               Jane Doe

Potresti usare

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

Questo creerebbe XML come segue

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

Rimozione del "Dipendente" da PATH rimuove i tag xml esterni in modo che questa query:

SELECT  Name
FROM    Employee
FOR XML PATH ('')

Creerebbe

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

Quello che stai facendo non è l'ideale, il nome della colonna 'data()' forza un errore sql perché sta tentando di creare un tag xml che non è un tag legale, quindi viene generato il seguente errore:

Il nome della colonna 'Data()' contiene un identificatore XML non valido come richiesto da FOR XML; '('(0x0028) è il primo carattere in errore.

La sottoquery correlata nasconde questo errore e genera semplicemente l'XML senza tag:

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

crea

John Smith Jane Doe

Stai quindi sostituendo gli spazi con le virgole, abbastanza autoesplicativo...

Fossi in te adatterei leggermente la query:

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; 

Non avere alias di colonna significa che non vengono creati tag xml e aggiungere la virgola all'interno della query select significa che qualsiasi nome con spazi non causerà errori,STUFF rimuoverà la prima virgola e lo spazio.

APPENDICE

Per approfondire ciò che KM ha detto in un commento, poiché questo sembra ottenere alcune visualizzazioni in più, il modo corretto per evitare i caratteri XML sarebbe usare .value come segue:

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;