Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Was bewirkt diese Abfrage, um eine durch Kommas getrennte Liste von SQL Server zu erstellen?

Am einfachsten lässt es sich erklären, wie FOR XML PATH funktioniert für aktuelles XML. Stellen Sie sich eine einfache Tabelle Employee vor :

EmployeeID      Name
1               John Smith
2               Jane Doe

Sie könnten

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

Dies würde XML wie folgt erstellen

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

Entfernen des „Employee“ aus PATH entfernt die äußeren XML-Tags, also diese Abfrage:

SELECT  Name
FROM    Employee
FOR XML PATH ('')

Würde erstellen

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

Was Sie dann tun, ist nicht ideal, der Spaltenname „data()“ erzwingt einen SQL-Fehler, da versucht wird, ein XML-Tag zu erstellen, das kein zulässiges Tag ist, sodass der folgende Fehler generiert wird:

Der Spaltenname 'Data()' enthält einen ungültigen XML-Bezeichner, wie von FOR XML gefordert; '('(0x0028) ist das erste fehlerhafte Zeichen.

Die korrelierte Unterabfrage verbirgt diesen Fehler und generiert nur das XML ohne Tags:

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

erstellt

John Smith Jane Doe

Sie ersetzen dann Leerzeichen durch Kommas, ziemlich selbsterklärend ...

An deiner Stelle würde ich die Abfrage leicht anpassen:

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; 

Wenn kein Spaltenalias vorhanden ist, werden keine XML-Tags erstellt, und das Hinzufügen des Kommas innerhalb der Auswahlabfrage bedeutet, dass alle Namen mit Leerzeichen keine Fehler verursachen,STUFF entfernt das erste Komma und Leerzeichen.

NACHTRAG

Um näher darauf einzugehen, was KM in einem Kommentar gesagt hat, da dies anscheinend ein paar weitere Aufrufe erhält, wäre der korrekte Weg, XML-Zeichen zu maskieren, die Verwendung von .value wie folgt:

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;