14th Mar 2023 18 Leseminuten 6 nützliche Beispiele für CTEs in SQL Server Tihomir Babic CTE MS SQL Server Inhaltsverzeichnis CTE-Syntax in SQL Server 6 Beispiele für CTEs in SQL Server 1: Ermitteln der durchschnittlichen Höchst- und Tiefstwerte der täglichen Datenströme 2: Berechnen Sie die durchschnittliche Gesamtvergütung pro Song 3: Finde das am meisten gestreamte Album jedes Künstlers 4: Berechnen Sie die durchschnittlichen Streams pro Song und vergleichen Sie sie mit den durchschnittlichen Streams pro Datum 5: Berechnen Sie den höchsten und den niedrigsten durchschnittlichen Albumpreis pro Künstler 6: Suche nach dem längsten Weg zwischen Rotterdam und Amsterdam Wann sollten Sie CTEs verwenden? CTEs sind das Tor zur Fortgeschrittenes SQL Nutzung! Wie können Sie CTEs in SQL Server in Ihrem Berufsalltag als Datenprofi verwenden? Diese Frage beantworten wir Ihnen anhand von sechs Beispielen. CTE ist die Abkürzung für Common Table Expression. Dabei handelt es sich um eine relativ neue Funktion in SQL Server, die mit SQL Server 2005 zur Verfügung gestellt wurde. Ein CTE ist ein temporäres, benanntes Ergebnis. Dieses Ergebnis ist nur für die Abfrage verfügbar, die es ausführt. Es wird nicht gespeichert, so dass es keinen Festplattenspeicher beansprucht. Eine CTE ist einer temporären Tabelle ähnlich und kann wie jede andere Tabelle verwendet werden. CTEs werden am häufigsten mit der Anweisung SELECT verwendet, können aber auch mit INSERT, UPDATE und DELETE verwendet werden. CTEs sind eines der anspruchsvollsten Konzepte in SQL Server. Um ihre Vorteile zu nutzen, sollten Sie sie sorgfältig strukturiert und nicht überstürzt erlernen. Unser Kurs Rekursive Abfragen in MS SQL Server zeigt Ihnen zunächst, wie Sie eine einfache CTE in SQL Server schreiben. Danach lernen Sie, mehrere CTEs zu schreiben, sie zu verschachteln und sie in SELECT, INSERT, UPDATE und DELETE Anweisungen zu verwenden. Schließlich lernen Sie etwas über hierarchische und grafische Datenstrukturen und wie Sie rekursive CTEs in SQL Server zur Abfrage solcher Daten verwenden können. Um sicherzustellen, dass Sie genug Übung bekommen, gibt es 112 interaktive Übungen, die Sie in diesem Kurs absolvieren können. Es gibt natürlich noch einige andere Möglichkeiten, CTEs zu lernen, die Sie sich ebenfalls ansehen können. CTE-Syntax in SQL Server Im Allgemeinen ist die CTE-Syntax in SQL Server wie im folgenden Beispiel dargestellt: WITH cte AS ( SELECT ... ) SELECT ... FROM cte; CTEs müssen immer mit dem Schlüsselwort WITH beginnen. Dann folgen der Name des CTE, das Schlüsselwort AS und die Klammern. In diesen Klammern definieren Sie den CTE. Wie Sie in unseren Beispielen sehen werden, bedeutet die Definition, dass Sie die Anweisung SELECT schreiben. Weitere Einzelheiten finden Sie in diesem Artikel, in dem erklärt wird, was eine CTE ist. 6 Beispiele für CTEs in SQL Server 1: Ermitteln der durchschnittlichen Höchst- und Tiefstwerte der täglichen Datenströme In den ersten fünf Beispielen verwenden wir denselben Datensatz. Er zeigt einige erfundene Daten von einer imaginären Musik-Streaming-Plattform, nennen wir sie Terpsichore. Der Datensatz besteht aus drei Tabellen. Die erste ist artistund hier ist die Abfrage zum Erstellen der Tabelle. Diese Tabelle enthält die folgenden Spalten: id - Die ID des Künstlers und den Primärschlüssel der Tabelle. artist_name - Der Name des Künstlers. idartist_name 1Prince 2Jimi Hendrix 3Santana Diese Tabelle enthält drei Künstler. Die nächste Tabelle ist albums. Hier ist die Abfrage, um sie zu erstellen. Und hier sind die Spalten, die sie enthält: id - Die ID des Albums und der Primärschlüssel der Tabelle. artist_id - Der Interpret (und der Fremdschlüssel der Tabelle). album_title - Der Titel des Albums. year_released - Das Jahr der Veröffentlichung des Albums. idartist_idalbum_titleyear_released 12Are You Experienced1967 22Axis: Bold as Love1967 31Dirty Mind1980 42Electric Ladyland1968 53Abraxas1970 6119991982 73Santana III1971 83Santana1969 91Prince1979 101Controversy1981 Es gibt zehn Alben in der Tabelle. Die letzte Tabelle ist streams. Sie zeigt die Streaming-Daten für die einzelnen Songs. Sie können die Tabelle mit dieser Abfrage erstellen. Und die Spalten: id - Die Stream-ID und der Primärschlüssel der Tabelle. artist_id - Die ID des Interpreten und ein Fremdschlüssel. album_id - Die ID des Albums und ein Fremdschlüssel. song_title - Der Name des Liedes. date - Das Datum des Streams. number_of_streams - Die Anzahl, wie oft der Titel an einem bestimmten Datum gespielt wurde. pay_per_stream - Der Wert (in Dollar), den Terpsichore an die Künstler für jeden Stream zahlt. idartist_idalbum_idsong_titledatenumber_of_streamspay_per_stream 119I Wanna Be Your Lover2023-01-015970.013 216Little Red Corvette2023-01-014970.013 316D.M.S.R.2023-01-012170.013 413Uptown2023-01-0197480.013 513Do It All Night2023-01-012080.013 Diese Tabelle enthält 45 Zeilen. Wir zeigen Ihnen nur die ersten fünf, damit Sie ein Gefühl für die Logik der Tabelle bekommen. Und nun das Beispiel! Beginnen wir damit, nur eine CTE in SQL Server zu schreiben. Damit berechnen wir die durchschnittliche höchste und niedrigste Anzahl der täglichen Streams. Hier ist der Code; wir werden ihn weiter unten erklären: WITH daily_streaming AS ( SELECT date, MIN(number_of_streams) AS minimum_streaming, MAX(number_of_streams) AS maximum_streaming FROM streams GROUP BY date ) SELECT AVG(minimum_streaming) AS average_minimum_daily_streaming, AVG(maximum_streaming) AS average_maximum__daily_streaming FROM daily_streaming; Eine CTE eignet sich hervorragend, um die Logik einer beliebigen Berechnung in SQL Server aufzuschlüsseln. Denken Sie daran, dass an einem Tag mehrere Songs gestreamt werden. Der Zweck unserer CTE ist es, die niedrigste und die höchste Anzahl von Streams pro Tag zu ermitteln. Wie bereits erwähnt, beginnt eine CTE in SQL Server immer mit dem Schlüsselwort WITH, dem der CTE-Name folgt. Unser CTE heißt daily_streaming. Nach dem Schlüsselwort AS folgt in Klammern eine Anweisung SELECT - also die CTE-Definition. Wir verwenden sie zusammen mit den Aggregatfunktionen MIN() und MAX(), um die höchste und niedrigste Anzahl von Streams nach Datum zu berechnen. Die nächste Anweisung SELECT verwendet Daten aus der CTE, auf die in der Klausel FROM verwiesen wird. Wie bereits erwähnt, kann eine CTE wie jede andere Tabelle verwendet werden. In dieser SELECT verwenden wir die Aggregatfunktion AVG(), um den Durchschnitt der täglichen Höchst- und Tiefstwerte der Datenströme zu ermitteln. Die Ausgabe zeigt, dass der durchschnittliche Tiefpunkt bei 90 Strömen liegt. Der Durchschnitt der höchsten täglichen Streams liegt bei 8.367. average_minimum_daily_streamingaverage_maximum__daily_streaming 908,367 2: Berechnen Sie die durchschnittliche Gesamtvergütung pro Song Jetzt wollen wir das Gelernte in der Praxis anwenden. Wir werden wieder eine einzelne CTE schreiben. Das zu lösende Problem besteht darin, die durchschnittliche Gesamtgebühr zu ermitteln, die Terpsichore für jeden Song bezahlt hat. Hier ist die Lösung: WITH paid_per_song AS ( SELECT song_title, SUM(number_of_streams * pay_per_stream) AS total_pay FROM streams GROUP BY id, song_title, pay_per_stream ) SELECT song_title, AVG(total_pay) AS average_total_pay FROM paid_per_song GROUP BY song_title ORDER BY average_total_pay DESC; Wir verwenden SQL Server CTE, um die Gesamtgebühr pro Song zu berechnen, indem wir die Anzahl der Streams mit der Gebühr pro Stream multiplizieren und dann mit der Aggregatfunktion SUM() summieren. An der CTE-Syntax ändert sich nichts: Zuerst kommt WITH, dann der CTE-Name, und danach kommt AS. Dann verwenden wir ein SELECT, das das CTE aufruft, um die durchschnittliche Vergütung pro Song zu berechnen. Es ist ganz einfach: Verwenden Sie AVG(), verweisen Sie auf die CTE in FROM und gruppieren Sie nach dem Titel des Liedes. Die Abfrage liefert das folgende Ergebnis: song_titleaverage_total_pay Uptown47.4803330 I Wanna Be Your Lover36.8203330 Little Red Corvette33.8693330 The Wind Cries Mary23.6138660 Do It All Night12.4063330 If 6 Was 97.7824000 Samba Pa Ti7.5735000 All Along the Watchtower5.2032000 Bold as Love4.7424000 Burning of the Midnight Lamp3.7333330 D.M.S.R.3.1633330 Taboo2.4871000 Jingo2.1604000 Everything's Coming Our Way1.5466000 Incident at Neshabur0.9207000 Wir sehen, dass der Song "Uptown" insgesamt 47,4803330 $ verdient hat. Die zweit- und drittplatzierten Songs nach Einnahmen sind "I Wanna Be Your Lover" und "Little Red Corvette". Wenn du ein Fan dieses Künstlers bist, dann brauchst du kein SQL, um herauszufinden, wer alle drei Songs geschrieben hat. 3: Finde das am meisten gestreamte Album jedes Künstlers In dieser Übung müssen Sie das am meisten gestreamte Album jedes Künstlers finden. Geben Sie den Namen des Künstlers, den Titel des Albums und die Anzahl der Streams pro Album aus. Auch hier handelt es sich um eine Abfrage mit nur einer CTE. Sie ist jedoch etwas komplexer als die beiden vorherigen - es gibt einige JOINs und eine Fensterfunktion. WITH album_streaming AS ( SELECT artist_id, album_id, SUM(number_of_streams) AS streams_by_album, RANK() OVER (PARTITION BY artist_id ORDER BY SUM(number_of_streams) DESC) AS streaming_rank FROM streams GROUP BY artist_id, album_id ) SELECT artist_name, album_title, streams_by_album FROM album_streaming alst JOIN albums al ON alst.album_id = al.id JOIN artist ar ON al.artist_id = ar.id WHERE streaming_rank = 1; Auch hier ist die CTE-Syntax in SQL Server vertraut. Konzentrieren wir uns also darauf, was diese CTE tut. Wir verwenden sie, um die Alben nach Künstler zu ordnen. Zunächst wählen wir die IDs von Künstler und Album aus. Dann verwenden wir SUM(), um die Anzahl der Streams pro Album zu berechnen. Jetzt kommt der entscheidende Teil - das Ranking der Ausgabe mit der Funktion RANK() window. Nach dem Aufruf der Funktion sehen wir die Klausel OVER() - eine obligatorische Klausel für SQL-Fensterfunktionen. Wir partitionieren den Datensatz nach der Künstler-ID und ordnen die Daten innerhalb jeder Partition nach der Anzahl der Streams in absteigender Reihenfolge. Was bedeutet das in der Praxis? Es bedeutet, dass die Fensterfunktion die Alben eines Interpreten in eine Rangfolge bringt, dann wird die Rangfolge neu gestartet, sobald die Funktion den nächsten Interpreten erreicht, und so weiter. Das Album des Künstlers mit den meisten Streams wird in seiner Partition an erster Stelle gereiht. Wenn Sie nur diese SELECT -Anweisung innerhalb der CTE ausführen, erhalten Sie diese Ausgabe: artist_idalbum_idstreams_by_albumstreaming_rank 1313,8201 168,5462 198,4973 257,7221 273,6672 281,9643 3111,0691 325,8712 344,1893 Wie Sie sehen können, werden die Alben des ersten Künstlers nach der Anzahl der Streams von der ersten bis zur dritten Stelle gereiht. Wenn wir den zweiten Künstler erreichen, beginnt die Rangfolge von neuem. Das Gleiche gilt für den dritten Künstler. Schauen wir uns nun an, was die zweite Anweisung SELECT bewirkt. Eigentlich ist es nichts Kompliziertes. Sie gibt den Namen des Künstlers und des Albums sowie die Anzahl der Streams zurück. Was diese Abfrage kompliziert macht, ist, dass wir drei Tabellen verknüpfen müssen. Die erste Verknüpfung ist die CTE album_streaming. Dann verbinden wir sie mit albums und dann mit der artist Tabelle. Am Ende filtern wir die Daten mit der WHERE Klausel, da wir nur an dem am meisten gestreamten Album interessiert sind. Sie erhalten dieses Ergebnis: artist_namealbum_titlestreams_by_album PrinceDirty Mind13,820 Jimi HendrixAre You Experienced11,069 SantanaAbraxas7,722 Das meistgestreamte Album von Prince ist "Dirty Mind" mit 13.820 Streams. Bei Jimi Hendrix ist das meistgestreamte Album "Are You Experienced" und bei Santana ist es "Abraxas". Bei dieser Lösung werden die Fensterfunktionen verwendet, daher hier eine Erinnerung daran, wie sie beim Ranking von Daten funktionieren. 4: Berechnen Sie die durchschnittlichen Streams pro Song und vergleichen Sie sie mit den durchschnittlichen Streams pro Datum Jetzt werden die Dinge etwas komplizierter. Aber nicht zu sehr, keine Sorge. Wir bauen auf dem auf, was wir bisher über CTEs in SQL Server gelernt haben. Hier müssen wir die durchschnittliche Anzahl der Streams pro Song ermitteln. Dann müssen wir die durchschnittliche Anzahl der Streams pro Datum berechnen. Die Ausgabe sollte beide Metriken zeigen. Außerdem sollte die Differenz zwischen dem durchschnittlichen Stream pro Song und dem täglichen Durchschnitt (als prozentuale Differenz), der Songtitel und die Daten angezeigt werden. Bis jetzt haben wir Abfragen mit einer CTE geschrieben. Dieses Mal besteht die Lösung aus zwei CTEs. Schauen wir uns an, wie das funktioniert: WITH streams_per_song AS ( SELECT song_title, AVG(number_of_streams) AS average_streams_per_song FROM streams GROUP BY song_title ), streams_per_date AS ( SELECT date, AVG(number_of_streams) AS average_streams_per_date FROM streams GROUP BY date ) SELECT song_title, average_streams_per_song, date, average_streams_per_date, (average_streams_per_song - average_streams_per_date)/CAST(average_streams_per_date AS DECIMAL(10,2))*100 AS diff_from_daily_average FROM streams_per_song, streams_per_date; Die erste CTE wird wie üblich geschrieben. Wir verwenden sie, um die durchschnittliche Anzahl der Streams pro Song mit AVG() zu berechnen. Nach dem Schließen der Klammern muss die erste CTE von der zweiten CTE mit einem Komma getrennt werden. Dann schreiben wir den zweiten CTE. Und siehe da! Es gibt keine WITH! Das ist richtig. Wenn Sie mehrere CTEs in eine Abfrage in SQL Server schreiben, schreiben Sie WITH nur vor die erste CTE. Die zweite (und jede folgende CTE) beginnt mit dem Namen der CTE; alles andere ist gleich. Diese zweite Abfrage dient zur Berechnung der durchschnittlichen Anzahl der Streams pro Datum. Auch hier verwenden wir die Funktion AVG(). Die dritte SELECT verwendet die Daten aus beiden CTEs. Sie gibt alle erforderlichen Spalten zurück. Die letzte Spalte ist diff_from_daily_average. Wir berechnen sie, indem wir die durchschnittlichen Streams pro Datum von den durchschnittlichen Streams pro Song abziehen. Die Differenz wird durch die durchschnittlichen Streams pro Datum geteilt und mit 100 multipliziert, um den Prozentsatz zu erhalten. Außerdem haben wir das Ergebnis mit der Funktion CAST() in einen dezimalen Datentyp umgewandelt. Aufgrund der Größe der Ausgabe zeigen wir nur die ersten paar Zeilen: song_titleaverage_streams_per_songdateaverage_streams_per_datediff_from_daily_average All Along the Watchtower8132023-01-011,031-21.14 Bold as Love7412023-01-011,031-28.13 Burning of the Midnight Lamp5832023-01-011,031-43.45 D.M.S.R.2432023-01-011,031-76.43 Do It All Night9542023-01-011,031-7.47 Die Daten zeigen, dass der durchschnittliche tägliche Stream für den 1. Januar 2023 1.031 beträgt. "All Along the Watchtower" liegt 21,14 % unter diesem Durchschnitt. Die nächsten beiden Songs liegen 28,13% und 43,45% unter dem Tagesdurchschnitt, und so weiter. 5: Berechnen Sie den höchsten und den niedrigsten durchschnittlichen Albumpreis pro Künstler Lassen Sie uns erklären, was wir damit meinen. Wir wollen zunächst die Durchschnittsvergütung nach Album und Datum ermitteln. Dann müssen wir den niedrigsten und den höchsten Gehaltswert pro Album ermitteln. Danach wollen wir die Daten nach Künstler aggregieren. Zusammen mit dem Namen des Künstlers müssen wir den Wert der niedrigsten Gage anzeigen, die der Künstler für ein Album erhalten hat. Dasselbe gilt für die höchste Gage für ein Album. Die Lösung in SQL Server enthält zwei CTEs. Dieses Mal handelt es sich jedoch um eine verschachtelte CTE. Das heißt, die zweite CTE verweist auf die erste CTE. Schauen wir uns an, wie das funktioniert: WITH pay_per_album AS ( SELECT album_id, date, AVG(number_of_streams * pay_per_stream) AS average_pay_per_album FROM streams GROUP BY album_id, date ), min_max_average_pay AS ( SELECT album_id, MIN(average_pay_per_album) AS lowest_average_pay_by_album, MAX(average_pay_per_album) AS highest_average_pay_by_album FROM pay_per_album GROUP BY album_id ) SELECT artist_name, MIN(lowest_average_pay_by_album) AS lowest_album_pay_by_artist, MAX(highest_average_pay_by_album) AS highest_album_pay_by_artist FROM min_max_average_pay mmap JOIN albums al ON mmap.album_id = al.id JOIN artist ar ON al.artist_id = ar.id GROUP BY artist_name; Seien Sie vorsichtig, wenn Sie die Code-Erklärung lesen! Es ist leicht, sich in all diesen Aggregationen zu verirren. Um die Sache einfacher zu machen, habe ich jeden Teil der Abfrage kopiert und mit einer Erklärung versehen. Wir beginnen mit der ersten CTE: WITH pay_per_album AS ( SELECT album_id, date, AVG(number_of_streams * pay_per_stream) AS average_pay_per_album FROM streams GROUP BY album_id, date ), Die erste CTE berechnet die durchschnittliche Vergütung pro Album und das Datum. Dazu wird die Anzahl der Streams mit dem Preis pro Stream multipliziert und AVG() verwendet. min_max_average_pay AS ( SELECT album_id, MIN(average_pay_per_album) AS lowest_average_pay_by_album, MAX(average_pay_per_album) AS highest_average_pay_by_album FROM pay_per_album GROUP BY album_id ) Wenn Sie die zweite CTE in SQL Server schreiben, ist die Syntax die gleiche wie im vorherigen Beispiel - keine zusätzlichen WITH, beginnen Sie mit dem CTE-Namen und trennen Sie die CTEs mit einem Komma. Der einzige Unterschied besteht darin, dass die zweite CTE diesmal auf die erste CTE und nicht auf das ursprüngliche Dataset verweist. Dieser verschachtelte CTE verwendet die Funktionen MIN() und MAX(), um für jedes Album den niedrigsten und höchsten Durchschnittslohn für alle Daten zu ermitteln. Die erste CTE wird in FROM referenziert. SELECT artist_name, MIN(lowest_average_pay_by_album) AS lowest_album_pay_by_artist, MAX(highest_average_pay_by_album) AS highest_album_pay_by_artist FROM min_max_average_pay mmap JOIN albums al ON mmap.album_id = al.id JOIN artist ar ON al.artist_id = ar.id GROUP BY artist_name; Schließlich gibt es SELECT, das den zweiten CTE mit den Funktionen albums und artist Tabellen verbindet. Wir wenden erneut die Funktionen MIN() und MAX() auf das Ergebnis der zweiten CTE an. Dies dient dazu, nur die Werte des niedrigsten und des höchsten gezahlten Preises aller Alben eines jeden Künstlers zurückzugeben. Nach Ausführung der Abfrage erhalten wir das folgende Ergebnis: artist_namelowest_album_pay_by_artisthighest_album_pay_by_artist Jimi Hendrix1.5963.19 Prince4.6497.31 Santana0.9110.22 6: Suche nach dem längsten Weg zwischen Rotterdam und Amsterdam Dies ist eine Abwandlung des Problems des kürzesten Pfades in der Graphentheorie, mit dem Unterschied, dass wir nach dem längsten Pfad suchen werden. Ein Graph ist eine Art Datenstruktur, die aus Knoten oder Punkten besteht, die durch Kanten verbunden sind. Da sie miteinander verbunden sind, ist es möglich, einen Weg von einem Knoten zum anderen zu finden, auch wenn sie nicht direkt miteinander verbunden sind. Stellen Sie sich das als eine Karte mit Straßen vor. Das ist genau das Beispiel, das wir hier verwenden werden. Unten sehen Sie die Tabelle cities_distancedie die Städte und die Entfernung zwischen ihnen anzeigt. Verwenden Sie diese Abfrage, um die Tabelle zu erstellen. Sie enthält diese Spalten: city_from - Die Ausgangsstadt. city_to - Die Ankunftsstadt. distance - Die Entfernung zwischen den beiden Städten, in Kilometern. Hier sind die Daten: city_fromcity_todistance RotterdamAmsterdam78.20 RotterdamGouda24.10 AmsterdamGouda72.50 GoudaLeiden34.10 AmsterdamLeiden50.00 RotterdamLeiden35.40 GoudaUtrecht44.00 UtrechtAmsterdam52.40 LeidenGouda34.10 Wir müssen den längsten Weg von Rotterdam nach Amsterdam finden. Der Weg sollte die Namen aller Städte entlang des Weges enthalten, getrennt durch '/'. Außerdem sollten wir die Länge des längsten Weges angeben. Wenn wir von dem längsten Weg sprechen, wollen wir Rundwege ausschließen (bei denen man endlos viele Runden machen und die Entfernung vergrößern kann). Wir wollen, dass dieser längste Weg nur einmal durch eine bestimmte Stadt führt. Um dieses Problem zu lösen, werden wir eine rekursive CTE verwenden. Dabei handelt es sich um eine Abfrage, die auf sich selbst verweist, bis sie das Ende der Daten erreicht. Diese Eigenschaft ist ideal für die Abfrage von Diagrammdaten, bei denen mehrere Wege zum gleichen Ziel führen können. Schauen wir uns an, wie diese rekursive CTE funktioniert: WITH longest_path AS ( SELECT cd.city_to, CAST((cd.city_from + '/' + cd.city_to) AS VARCHAR(100)) AS path, cd.distance AS distance FROM cities_distance cd WHERE cd.city_from = 'Rotterdam' UNION ALL SELECT cd.city_to, CAST((lp.path + '/' + cd.city_to) AS VARCHAR(100)) AS path, CAST((lp.distance + cd.distance) AS DECIMAL(10,2)) FROM longest_path lp INNER JOIN cities_distance cd ON cd.city_from = lp.city_to WHERE lp.city_to <> 'Amsterdam' AND lp.path NOT LIKE '%/' + cd.city_to + '/%' ) SELECT TOP 1 lp.path, lp.distance FROM longest_path lp WHERE lp.city_to = 'Amsterdam' ORDER BY lp.distance DESC; Die Syntax sieht genauso aus wie zuvor - die rekursive Abfrage beginnt auch in SQL Server mit WITH. Wie üblich gibt es eine SELECT -Anweisung in den Klammern. Es sind zwei, um genau zu sein. Schauen wir uns an, was die erste Anweisung bewirkt. WITH longest_path AS ( SELECT cd.city_to, CAST((cd.city_from + '/' + cd.city_to) AS VARCHAR(100)) AS path, cd.distance AS distance FROM cities_distance cd WHERE cd.city_from = 'Rotterdam' Die erste SELECT in der Rekursion wird Ankermitglied genannt. Es wird verwendet, um den Startpunkt der Rekursion zu bestimmen. Der Startpunkt wird Rotterdam sein, was wir durch Filtern dieser Stadt in WHERE erhalten. Die Spalte city_to wird verwendet, um alle Endziele anzuzeigen, die direkt von Rotterdam aus erreicht werden können. In der Spalte path werden alle Ausgangs- und Zielorte aufgelistet. Die Länge dieser Route wird in der Spalte distance angezeigt. Dann folgt UNION ALL, die die Ergebnisse des Ankers und des rekursiven Mitglieds, d.h. der zweiten SELECT, verbindet. Die Zusammenführung dieser beiden Abfragen ist notwendig, damit die Rekursion funktioniert. Hinweis: In einigen anderen SQL-Dialekten ist es auch möglich, UNION zu verwenden. SQL Server erlaubt jedoch nur UNION ALL. Nun kommen wir zu dem rekursiven Mitglied. Es referenziert das CTE selbst in FROM und verbindet es mit der Tabelle cities_distance. Damit die Abfragen vereinigt werden können, müssen sie beide die gleiche Anzahl von Spalten desselben Datentyps haben. Die ersten beiden Spalten sind die gleichen wie im Ankermitglied. Die Spalte longest_path summiert alle Entfernungen, um alle Städte von Rotterdam aus zu erreichen. SELECT cd.city_to, CAST((lp.path + '/' + cd.city_to) AS VARCHAR(100)) AS path, CAST((lp.distance + cd.distance) AS DECIMAL(10,2)) FROM longest_path lp INNER JOIN cities_distance cd ON cd.city_from = lp.city_to WHERE lp.city_to <> 'Amsterdam' AND lp.path NOT LIKE '%/' + cd.city_to + '/%' ) Wir haben auch zwei Bedingungen in WHERE hinzugefügt. Die erste schließt alle Beziehungen aus, bei denen Amsterdam das Endziel ist; wir suchen den längsten, nicht den kürzesten Weg nach Amsterdam. Die zweite Bedingung stellt sicher, dass jede neue Stadt, die dem Pfad hinzugefügt wird, nicht bereits in diesem Pfad enthalten ist. Andernfalls würde die Abfrage in eine endlose Rekursion münden. Dies entspricht dem oben Gesagten: Der längste Weg sollte nicht mehr als einmal in dieselbe Stadt führen. Um besser zu verstehen, wovon wir sprechen, sehen Sie hier die Ausgabe der rekursiven CTE: city_topathdistance AmsterdamRotterdam/Amsterdam78.20 GoudaRotterdam/Gouda24.10 LeidenRotterdam/Leiden35.40 GoudaRotterdam/Leiden/Gouda69.50 UtrechtRotterdam/Leiden/Gouda/Utrecht113.50 AmsterdamRotterdam/Leiden/Gouda/Utrecht/Amsterdam165.90 LeidenRotterdam/Gouda/Leiden58.2 UtrechtRotterdam/Gouda/Utrecht68.1 AmsterdamRotterdam/Gouda/Utrecht/Amsterdam120.5 Sie können sehen, dass es drei Wege von Rotterdam nach Amsterdam gibt. Eine ist direkt, die Entfernung beträgt 78,20 km. Der zweite und dritte Weg führen über andere Städte und sind 165,90 bzw. 120,50 km lang. Wohlgemerkt, dies ist nicht das Endergebnis! Unsere Lösung enthält auch eine SELECT -Anweisung, die auf das CTE verweist: SELECT TOP 1 lp.path, lp.distance FROM longest_path lp WHERE lp.city_to = 'Amsterdam' ORDER BY lp.distance DESC; Diese SELECT gibt den Weg und die Entfernung zurück. Wir verwenden den Befehl TOP 1 in Kombination mit ORDER BY, um den längsten Weg von Rotterdam nach Amsterdam zu ermitteln. Wir haben die Daten von der längsten bis zur kürzesten Entfernung sortiert, so dass die erste Zeile auch die längste Strecke ist. Hier ist das Endergebnis: pathdistance Rotterdam/Leiden/Gouda/Utrecht/Amsterdam165.90 Diese Ausgabe zeigt, dass der längste Weg von Rotterdam nach Amsterdam 165,9 km beträgt und über Leiden, Gouda und Utrecht führt. Wenn Sie von diesem Thema nicht genug bekommen können, finden Sie hier noch einige weitere CTE-Beispiele. Wann sollten Sie CTEs verwenden? Wie Sie in unseren Beispielen gesehen haben, hat eine CTE in SQL Server viele Funktionen. Einer davon ist, dass sie im Allgemeinen die Lesbarkeit des Codes verbessert. Alle oben genannten Lösungen (außer der Rekursion) hätten auch mit Unterabfragen geschrieben werden können. Aber das würde den Code viel länger und unübersichtlicher machen. Die Unterabfragen werden in der Regel entgegen der Logik des Problems geschrieben, das man zu lösen versucht. Sie haben zunächst die Hauptabfrage, die die Ausgabe der Unterabfrage verwendet. Die Unterabfrage ist also in der Regel der erste Schritt der Berechnung, auch wenn sie im Code nicht so platziert ist. CTEs hingegen können so geschrieben werden, dass sie der Logik des Problems folgen. Sie können mehrere separate CTEs schreiben und ihre Ausgaben in die SELECT Anweisungen einbinden. Sie können auch auf die Ausgabe einer CTE mit der zweiten Abfrage (oder dritten, vierten...) verweisen, wobei die letzte SELECT Anweisung eine weitere Berechnungsebene darstellt. In einem der Beispiele wurde auch gezeigt, wie man Daten in SQL Server mit Hilfe einer Fensterfunktion und einer CTE einordnen kann. Und wenn Sie rekursive Abfragen in SQL Server schreiben wollen, geht das nicht ohne CTEs. Ein CTE kann nicht rekursiv sein, aber ohne CTE gibt es keine rekursiven Abfragen. Neben Graphen ist die Rekursion äußerst hilfreich bei der Abfrage hierarchischer Strukturen, wie z. B. der Datenorganisation und von Stammbäumen. Mehr über die Verwendung von CTEs finden Sie hier. CTEs sind das Tor zur Fortgeschrittenes SQL Nutzung! CTEs sind eines der fortgeschritteneren SQL Server-Konzepte. Wenn Sie sich die Tür zu fortgeschrittenen SQL Server-Fähigkeiten öffnen wollen, sind CTEs ein Muss. Wenn Ihre Abfragen in SQL Server immer komplexer werden, werden Sie bald feststellen, dass das Erlernen von CTEs eine der besten Entscheidungen war, die Sie je getroffen haben. Sie sind auch ein Sprungbrett für rekursive Abfragen, mit denen Sie ungewöhnliche Arten von Datenstrukturen in SQL Server abfragen können, z. B. Hierarchien und Diagramme. Dieser Artikel ist nur eine Vorschau auf das Wissen, das Sie im Kurs Rekursive Abfragen in MS SQL Server finden können. Hören Sie hier also nicht auf. Es gibt noch viel mehr zu lernen! Tags: CTE MS SQL Server