2012-04-30 5 views
11

Ich habe diese Abfrage mit Hilfe von Google geschrieben, um eine getrennte Liste aus einer Tabelle zu erstellen, aber ich habe nichts aus dieser Abfrage verstanden.Was bewirkt diese Abfrage zum Erstellen einer kommagetrennten Liste SQL Server?

Kann mir jemand erklären, was passiert

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; 

mich Ergebnis gibt

10 CLARK, KING, MILLER 
20 SMITH, JONES, SCOTT, ADAMS, FORD 
30 ALLEN, WARD, MARTIN, BLAKE, TURNER, JAMES 
+1

** Bitte beachten Sie, dass der Code für Text mit Zeichen wie><& scheitern ** Sie Charakter Expansion erhalten '<', '>' '' & es einen besseren Weg, diese Verkettung finden Sie unter: http://Stackoverflow.com/a/5031297/65223 –

Antwort

35

Die einfachste Möglichkeit, es zu erklären, ist zu sehen, wie FOR XML PATH für tatsächliche XML funktioniert.Dies würde XML erstellen wie folgt

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

die 'Mitarbeiter' aus PATH Beim Entfernen der äußeren XML-Tags diese

EmployeeID  Name 
1    John Smith 
2    Jane Doe 

Sie

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

verwenden: eine einfache Tabelle vorstellen Employee Abfrage:

SELECT Name 
FROM Employee 
FOR XML PATH ('') 

Würde

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

erstellen Was Sie tun, dann ist nicht ideal, die Spaltennamen ‚Daten()‘ erzwingt einen SQL-Fehler, weil es versucht, ein XML-Tag zu erstellen, das keine juristische Tag ist, so Der folgende Fehler wird generiert:

Spaltenname 'Data()' enthält eine ungültige XML-Kennung wie von FOR XML erforderlich; '(' (0x0028) ist das erste Zeichen Schuld

Die korrelierte Unterabfrage diesen Fehler versteckt und erzeugt nur die XML ohne tags:.

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

schafft

John Smith Jane Doe 

Sie dann werden Leerzeichen durch Kommas ersetzt, ziemlich selbsterklärend ...

Wenn ich du wäre würde ich die Abfrage etwas 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; 

kein Spalt-Alias ​​wird in der SELECT-Abfrage keine XML-Tags erstellt werden, und das Hinzufügen des Kommas bedeuten bedeutet keine Namen mit Leerzeichen in nicht zu Fehlern führen, STUFF das erste Komma und Leerzeichen entfernen.

NACHTRAG

Um sich zu erarbeiten, was KM in einem Kommentar gesagt hat, als dies der richtige Weg XML-Zeichen immer noch ein paar Ansichten zu sein scheint, zu entkommen wäre .value wie folgt zu verwenden:

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; 
+1

Sehr gute Erklärung danke! –

+3

+1 gute Erklärung, aber ** BITTE BEACHTEN SIE, DIESER CODE WIRD FÄLLT FÜR TEXT MIT ZEICHEN WIE><& ** Sie werden Zeichenerweiterung wie '<', '>' '&' gibt es eine bessere Möglichkeit, diese Verkettung zu tun , siehe: http://Stackoverflow.com/a/5031297/65223 –

+1

Sie vermissen ein einzelnes Anführungszeichen, um 'NVARCHAR (MAX) 'zu beenden – wilsjd

0

Die äußere Abfrage ruft eine Liste der Abteilungsnummern und die Unterabfrage wird dann laufen für jede Nummer Abteilung alle zurückkehren Namen, die zu dieser Abteilung gehören. Die Unterabfrage verwendet die FOR XML-Anweisung, um die Ausgabe in eine durch Kommas getrennte Liste zu formatieren.

6

Schritt für Schritt auseinander nehmen - von innen nach außen.

Schritt 1:

Führen Sie die innerste Abfrage und sehen, was es produziert:

SELECT E2.ename AS 'data()' 
FROM emp AS e2 
WHERE e2.DEPTNO = 10 
FOR XML PATH('') 

Sie sollten eine Ausgabe etwas wie bekommen:

CLARK KING MILLER 

Schritt 2:

Die REPLACE ersetzt nur Räume mit , - und damit die Ausgabe in

drehen
CLARK, KING, MILLER 

Schritt 3:

Die äußere Abfrage erhält den deptno Wert - und die Ergebnisse aus der inneren Abfrage - und produziert Ihre endgültige Ergebnis.

1

SQL Server 2017 macht dies viel einfacher mit der new STRING_AGG. Ich bin kürzlich auf diesen Beitrag gestoßen und habe meine Strategie STUFF/FOR XML umgestellt, um die neue String-Funktion zu verwenden. Außerdem wird vermieden, dass eine zusätzliche JOIN/SUBQUERY und der Overhead von FOR XML (und die ungeraden Codierungsprobleme) und schwer zu interpretierendes SQL erforderlich sind.

SELECT E1.deptno, 
     STRING_AGG(E1.ename, ', ') AS allemp 
FROM EMP AS e1 
GROUP BY DEPTNO; 

Hinweis: Auch sicher sein, zu check out the counterpart STRING_SPLIT mit SQL begrenzt Daten viel einfacher zu machen.

Verwandte Themen