it-swarm.com.de

Wie Stuff und 'For Xml Path' in SQL Server funktionieren

Tabelle ist:

+----+------+
| Id | Name |
+----+------+    
| 1  | aaa  |
| 1  | bbb  |
| 1  | ccc  |
| 1  | ddd  |
| 1  | eee  |
+----+------+

Erforderliche Ausgabe:

+----+---------------------+
| Id |        abc          |
+----+---------------------+ 
|  1 | aaa,bbb,ccc,ddd,eee |
+----+---------------------+

Abfrage:

SELECT ID, 
    abc = STUFF(
                 (SELECT ',' + name FROM temp1 FOR XML PATH ('')), 1, 1, ''
               ) 
FROM temp1 GROUP BY id

Diese Abfrage funktioniert ordnungsgemäß. Aber ich brauche nur die Erklärung, wie es funktioniert oder gibt es einen anderen oder kurzen Weg, um dies zu tun.

Ich bin sehr verwirrt, das zu verstehen.

300
Puneet Chawla

So funktioniert es:

1. Holen Sie sich XML-Element-String mit FOR XML

Wenn Sie FOR XML PATH am Ende einer Abfrage hinzufügen, können Sie die Ergebnisse der Abfrage als XML-Elemente mit dem im PATH-Argument enthaltenen Elementnamen ausgeben. Wenn wir zum Beispiel die folgende Anweisung ausführen würden:

SELECT ',' + name 
              FROM temp1
              FOR XML PATH ('')

Durch die Übergabe einer leeren Zeichenfolge (FOR XML PATH ('')) erhalten wir stattdessen Folgendes:

,aaa,bbb,ccc,ddd,eee

2. Entfernen Sie das Komma mit STUFF

Die Anweisung STUFF "stopft" buchstäblich eine Zeichenfolge in eine andere und ersetzt Zeichen in der ersten Zeichenfolge. Wir verwenden sie jedoch nur, um das erste Zeichen der resultierenden Werteliste zu entfernen.

SELECT abc = STUFF((
            SELECT ',' + NAME
            FROM temp1
            FOR XML PATH('')
            ), 1, 1, '')
FROM temp1

Die Parameter von STUFF sind:

  • Die Zeichenfolge, die „gestopft“ werden soll (in unserem Fall die vollständige Liste der Namen mit einem führenden Komma)
  • Der Ort, an dem mit dem Löschen und Einfügen von Zeichen begonnen werden soll (1)
  • Die Anzahl der zu löschenden Zeichen (1 als führendes Komma)

Am Ende haben wir also:

aaa,bbb,ccc,ddd,eee

. Tragen Sie sich bei id ein, um die vollständige Liste zu erhalten

Als nächstes fügen wir dies einfach in die Liste der IDs in der temporären Tabelle ein, um eine Liste der IDs mit Namen zu erhalten:

SELECT ID,  abc = STUFF(
             (SELECT ',' + name 
              FROM temp1 t1
              WHERE t1.id = t2.id
              FOR XML PATH (''))
             , 1, 1, '') from temp1 t2
group by id;

Und wir haben unser Ergebnis:

-----------------------------------
| Id        | Name                |
|---------------------------------|
| 1         | aaa,bbb,ccc,ddd,eee |
-----------------------------------

Hoffe das hilft!

577
FutbolFan

Dieser Artikel behandelt verschiedene Arten der Verkettung von Zeichenfolgen in SQL, einschließlich einer verbesserten Version Ihres Codes, die die verketteten Werte nicht XML-codiert.

SELECT ID, abc = STUFF
(
    (
        SELECT ',' + name
        FROM temp1 As T2
        -- You only want to combine rows for a single ID here:
        WHERE T2.ID = T1.ID
        ORDER BY name
        FOR XML PATH (''), TYPE
    ).value('.', 'varchar(max)')
, 1, 1, '')
FROM temp1 As T1
GROUP BY id

Beginnen Sie mit der inneren Abfrage, um zu verstehen, was passiert:

SELECT ',' + name
FROM temp1 As T2
WHERE T2.ID = 42 -- Pick a random ID from the table
ORDER BY name
FOR XML PATH (''), TYPE

Da Sie FOR XML angeben, erhalten Sie eine einzelne Zeile mit einem XML-Fragment, das alle Zeilen darstellt.

Da Sie für die erste Spalte keinen Spaltenalias angegeben haben, wird jede Zeile in ein XML-Element mit dem in Klammern nach dem FOR XML PATH angegebenen Namen eingeschlossen. Wenn Sie beispielsweise FOR XML PATH ('X') hätten, erhalten Sie ein XML-Dokument, das wie folgt aussieht:

<X>,aaa</X>
<X>,bbb</X>
...

Da Sie jedoch keinen Elementnamen angegeben haben, erhalten Sie nur eine Liste mit Werten:

,aaa,bbb,...

Die Funktion .value('.', 'varchar(max)') ruft einfach den Wert aus dem resultierenden XML-Fragment ab, ohne "Sonderzeichen" zu codieren. Sie haben jetzt eine Zeichenfolge, die wie folgt aussieht:

',aaa,bbb,...'

Die STUFF -Funktion entfernt dann das führende Komma und gibt Ihnen ein Endergebnis, das wie folgt aussieht:

'aaa,bbb,...'

Auf den ersten Blick sieht es ziemlich verwirrend aus, aber im Vergleich zu einigen anderen Optionen ist es in der Regel recht leistungsfähig.

66
Richard Deeming

Der PATH-Modus wird zum Generieren von XML aus einer SELECT-Abfrage verwendet

1. SELECT   
       ID,  
       Name  
FROM temp1
FOR XML PATH;  

Ouput:
<row>
<ID>1</ID>
<Name>aaa</Name>
</row>

<row>
<ID>1</ID>
<Name>bbb</Name>
</row>

<row>
<ID>1</ID>
<Name>ccc</Name>
</row>

<row>
<ID>1</ID>
<Name>ddd</Name>
</row>

<row>
<ID>1</ID>
<Name>eee</Name>
</row>

Die Ausgabe ist elementzentriertes XML, bei dem jeder Spaltenwert im resultierenden Rowset in ein Zeilenelement eingeschlossen wird. Da in der SELECT-Klausel keine Aliase für die Spaltennamen angegeben sind, stimmen die generierten untergeordneten Elementnamen mit den entsprechenden Spaltennamen in der SELECT-Klausel überein.

Für jede Zeile im Rowset wird ein Tag hinzugefügt.

2.
SELECT   
       ID,  
       Name  
FROM temp1
FOR XML PATH('');

Ouput:
<ID>1</ID>
<Name>aaa</Name>
<ID>1</ID>
<Name>bbb</Name>
<ID>1</ID>
<Name>ccc</Name>
<ID>1</ID>
<Name>ddd</Name>
<ID>1</ID>
<Name>eee</Name>

Für Schritt 2: Wenn Sie eine Zeichenfolge mit der Länge Null angeben, wird das Umbruchelement nicht erstellt.

3. 

    SELECT   

           Name  
    FROM temp1
    FOR XML PATH('');

    Ouput:
    <Name>aaa</Name>
    <Name>bbb</Name>
    <Name>ccc</Name>
    <Name>ddd</Name>
    <Name>eee</Name>

4. SELECT   
        ',' +Name  
FROM temp1
FOR XML PATH('')

Ouput:
,aaa,bbb,ccc,ddd,eee

In Schritt 4 verketten wir die Werte.

5. SELECT ID,
    abc = (SELECT   
            ',' +Name  
    FROM temp1
    FOR XML PATH('') )
FROM temp1

Ouput:
1   ,aaa,bbb,ccc,ddd,eee
1   ,aaa,bbb,ccc,ddd,eee
1   ,aaa,bbb,ccc,ddd,eee
1   ,aaa,bbb,ccc,ddd,eee
1   ,aaa,bbb,ccc,ddd,eee


6. SELECT ID,
    abc = (SELECT   
            ',' +Name  
    FROM temp1
    FOR XML PATH('') )
FROM temp1 GROUP by iD

Ouput:
ID  abc
1   ,aaa,bbb,ccc,ddd,eee

In Schritt 6 gruppieren wir das Datum nach ID.

STUFF (source_string, start, length, add_string) Parameter oder Argumente source_string Die zu ändernde Quellzeichenfolge. Start Die Position in der Quellzeichenfolge, um Längenzeichen zu löschen und dann add_string einzufügen. Length Die Anzahl der Zeichen, die aus der Quellzeichenfolge zu löschen sind. Add_string Die Zeichenfolge, die an der Startposition in den Quelltext eingefügt werden soll.

SELECT ID,
    abc = 
    STUFF (
        (SELECT   
                ',' +Name  
        FROM temp1
        FOR XML PATH('')), 1, 1, ''
    )
FROM temp1 GROUP by iD

Output:
-----------------------------------
| Id        | Name                |
|---------------------------------|
| 1         | aaa,bbb,ccc,ddd,eee |
-----------------------------------
36
Neha Chopra

Es gibt sehr neue Funktionen in Azure SQL-Datenbank und SQL Server (ab 2017), um genau dieses Szenario zu handhaben. Ich glaube, dass dies als native offizielle Methode für das dienen würde, was Sie mit der XML/STUFF-Methode erreichen möchten. Beispiel:

select id, STRING_AGG(name, ',') as abc
from temp1
group by id

STRING_AGG - https://msdn.Microsoft.com/en-us/library/mt790580.aspx

BEARBEITEN: Als ich dies ursprünglich veröffentlichte, erwähnte ich SQL Server 2016, da ich dachte, dass ich dies bei einem potenziellen Feature sah, das aufgenommen werden sollte. Entweder habe ich mich daran erinnert oder etwas hat sich geändert, danke für die vorgeschlagene Änderung, die die Version repariert. Außerdem war ich ziemlich beeindruckt und war mir des mehrstufigen Überprüfungsprozesses nicht voll bewusst, der mich gerade für eine letzte Option reingezogen hat.

17
Brian Jorden

Wenn wir in for xml path einen Wert wie [ for xml path('ENVLOPE') ] definieren, werden diese Tags mit jeder Zeile hinzugefügt:

<ENVLOPE>
</ENVLOPE>
4
vikas
SELECT ID, 
    abc = STUFF(
                 (SELECT ',' + name FROM temp1 FOR XML PATH ('')), 1, 1, ''
               ) 
FROM temp1 GROUP BY id

Hier in der obigen Abfrage wird die Funktion STUFF verwendet, um nur das erste Komma (,) aus der generierten XML-Zeichenfolge (,aaa,bbb,ccc,ddd,eee) zu entfernen, dann wird es (aaa,bbb,ccc,ddd,eee).

Und FOR XML PATH('') konvertiert einfach Spaltendaten in (,aaa,bbb,ccc,ddd,eee)-String, aber in PATH übergeben wir '', sodass kein XML-Tag erstellt wird.

Und am Ende haben wir Datensätze mithilfe der Spalte ID gruppiert.

Declare @Temp As Table (Id Int,Name Varchar(100))
Insert Into @Temp values(1,'A'),(1,'B'),(1,'C'),(2,'D'),(2,'E'),(3,'F'),(3,'G'),(3,'H'),(4,'I'),(5,'J'),(5,'K')
Select X.ID,
stuff((Select ','+ Z.Name from @Temp Z Where X.Id =Z.Id For XML Path('')),1,1,'')
from @Temp X
Group by X.ID
1
Omkar Naik

Ich habe das Debuggen durchgeführt und schließlich meine 'vollgestopfte' Abfrage zurückgegeben, es ist normal.

Einfach

select * from myTable for xml path('myTable')

gibt mir den Inhalt der Tabelle, um von einem Trigger, den ich debugge, in eine Protokolltabelle zu schreiben.

1
SlavaTT