25th Jun 2024 8 Leseminuten Was ist ein gemeinsamer Tabellenausdruck (CTE) in SQL? Ignacio L. Bisso CTE Inhaltsverzeichnis CTEs helfen bei der Vereinfachung von Abfragen Lernen von SQL Common Table Expressions anhand von Beispielen Verwendung von CTEs in Fortgeschrittenes SQL Abfragen Verschachtelte CTEs in SQL-Abfragen Rekursive Abfragen und Gemeinsame Tabellenausdrücke SQL CTEs sind eine mächtige Ressource Der gemeinsame Tabellenausdruck (CTE) ist ein leistungsfähiges Konstrukt in SQL, das eine Abfrage vereinfacht. CTEs funktionieren wie virtuelle Tabellen (mit Datensätzen und Spalten), die während der Ausführung einer Abfrage erstellt, von der Abfrage verwendet und nach der Ausführung der Abfrage gelöscht werden. CTEs dienen oft als Brücke, um die Daten in den Quelltabellen in das von der Abfrage erwartete Format umzuwandeln. Frage: Was ist ein gemeinsamer Tabellenausdruck in SQL? Ein Common Table Expression (CTE) ist wie eine benannte Unterabfrage. Er funktioniert wie eine virtuelle Tabelle, auf die nur die Hauptabfrage zugreifen kann. CTEs können helfen, Ihren Code zu vereinfachen, zu verkürzen und zu organisieren. Ein gemeinsamer Tabellenausdruck (Common Table Expression, CTE) ist eine temporäre benannte Ergebnismenge, die aus einer einfachen SELECT -Anweisung erstellt wird und in einer nachfolgenden SELECT -Anweisung verwendet werden kann. Jeder SQL CTE ist wie eine benannte Abfrage, deren Ergebnis in einer virtuellen Tabelle (einem CTE) gespeichert wird, auf die später in der Hauptabfrage verwiesen werden kann. Der beste Weg, gemeinsame Tabellenausdrücke zu lernen, ist die Praxis. Ich empfehle LearnSQL.de's interaktiven Rekursive Abfragen Kurs. Er enthält über 100 Übungen, in denen CTEs gelehrt werden, angefangen bei den Grundlagen bis hin zu fortgeschrittenen Themen wie rekursiven allgemeinen Tabellenausdrücken. CTEs helfen bei der Vereinfachung von Abfragen Beginnen wir mit der Syntax eines gemeinsamen Tabellenausdrucks. WITH my_cte AS ( SELECT a,b,c FROM T1 ) SELECT a,c FROM my_cte WHERE .... Der Name dieses CTEs lautet my_cteund die CTE-Abfrage lautet SELECT a,b,c FROM T1. Die CTE-Abfrage beginnt mit dem Schlüsselwort WITH. Danach geben Sie den Namen Ihrer CTE-Abfrage an und anschließend den Inhalt der Abfrage in Klammern. Die Hauptabfrage steht nach der schließenden Klammer und bezieht sich auf die CTE. Hier lautet die Hauptabfrage (auch als äußere Abfrage bezeichnet) SELECT a,c FROM my_cte WHERE …. In diesem ausgezeichneten Einführungsartikel über CTEs finden Sie viele Beispiele für den Einstieg. Weitere einführende Artikel sind "Improving Query Readability with Common Table Expressions" und "When Should I Use a Common Table Expression (CTE)?", in denen gängige Tabellenausdrücke erklärt werden. Lernen von SQL Common Table Expressions anhand von Beispielen In diesem Abschnitt stellen wir einige Beispiele für SQL-Abfragen vor, die allgemeine Tabellenausdrücke verwenden. Alle Beispiele basieren auf einer Datenbank für eine Kette von Mobiltelefongeschäften. Die Tabelle sales(siehe unten) enthält einen Datensatz pro verkauftem Produkt: branchdateselleritemquantityunit_price Paris-12021-12-07CharlesHeadphones A2180 London-12021-12-06JohnCell Phone X22120 London-22021-12-07MaryHeadphones A1160 Paris-12021-12-07CharlesBattery Charger150 London-22021-12-07MaryCell Phone B2290 London-12021-12-07JohnHeadphones A0575 London-12021-12-07SeanCell Phone X12100 Im ersten Beispiel erhalten wir einen Bericht mit denselben Datensätzen aus der Tabelle sales Tabelle, fügen aber eine zusätzliche Spalte mit dem Preis des teuersten Artikels hinzu, der an diesem Tag in der gleichen Filiale verkauft wurde. Um den Preis des teuersten Artikels zu erhalten, verwenden wir einen allgemeinen Tabellenausdruck wie diesen: WITH highest AS ( SELECT branch, date, MAX(unit_price) AS highest_price FROM sales GROUP BY branch, date ) SELECT sales.*, h.highest_price FROM sales JOIN highest h ON sales.branch = h.branch AND sales.date = h.date Diese Abfrage definiert eine SQL CTE namens highest deren Ergebnis eine virtuelle Tabelle erzeugt. Die virtuelle Tabelle hat die Spalten Filiale, Datum und highest_price, die jeweils den Namen der Filiale, das Datum und den höchsten an diesem Tag in dieser Filiale verkauften Stückpreis enthalten. Dann wird die äußere Abfrage ausgeführt, die die highest virtuelle Tabelle verwendet, als wäre sie eine reguläre Tabelle. Schließlich verbinden wir das Ergebnis der CTE highest mit der sales Tabelle. Das Ergebnis der gesamten Abfrage ist unten dargestellt: branchdateselleritemquantityunit_pricehighest_ price Paris-12021-12-07CharlesHeadphones A218080 London-12021-12-06JohnCell Phone X22120120 London-22021-12-07MaryHeadphones A116090 Paris-12021-12-07CharlesBattery Charger15080 London-22021-12-07MaryCell Phone B229090 London-12021-12-07JohnHeadphones A0575100 London-12021-12-07SeanCell Phone X12100100 Im nächsten Beispiel erstellen wir einen Bericht mit den höchsten Tageseinnahmen nach Filialen. WITH daily_revenue AS ( SELECT branch, date, SUM(unit_price * quantity) AS daily_revenue FROM sales WHERE EXTRACT(YEAR FROM date) = 2021 GROUP BY 1,2 ) SELECT branch, MAX(daily_revenue) max_daily_revenue FROM daily_revenue GROUP BY 1 ORDER BY 2 DESC In dieser Abfrage hat eine CTE namens daily_revenue mit den Spalten Branche, Datum und daily_revenue für jedes Datum im Jahr 2021. In der äußeren Abfrage erhalten wir dann den höchsten Umsatzbetrag für jede Filiale im Jahr 2021. Der Bericht ist nach max_daily_revenue in absteigender Reihenfolge geordnet. Nachfolgend finden Sie die Ergebnisse dieser Abfrage. branchmax_daily_revenue London-1575 London-2240 Paris-1135 Verwendung von CTEs in Fortgeschrittenes SQL Abfragen Sie können zwei oder mehr CTEs definieren und sie in der Hauptabfrage verwenden. Im nächsten Beispiel zeigen wir Ihnen, wie Sie eine lange Abfrage mithilfe von SQL CTEs aufteilen und organisieren können. Durch die Benennung verschiedener Teile der Abfrage machen CTEs die Abfrage übersichtlicher. Angenommen, wir möchten einen Bericht mit den monatlichen Gesamteinnahmen in London im Jahr 2021, aber wir möchten auch die Einnahmen für jede Filiale in London in demselben Bericht haben. Hier erstellen wir zwei CTEs und fügen sie dann in der Hauptabfrage zusammen. WITH london1_monthly_revenue AS ( SELECT EXTRACT(MONTH FROM date) as month, SUM(unit_price * quantity) AS revenue FROM sales WHERE EXTRACT(YEAR FROM date) = 2021 AND branch = 'London-1' GROUP BY 1 ), london2_monthly_revenue AS ( SELECT EXTRACT(MONTH FROM date) as month, SUM(unit_price * quantity) AS revenue FROM sales WHERE EXTRACT(YEAR FROM date) = 2021 AND branch = 'London-2' GROUP BY 1 ) SELECT l1.month, l1.revenue + l2.revenue AS london_revenue, l1.revenue AS london1_revenue, l2.revenue AS london2_revenue FROM london1_monthly_revenue l1, london2_monthly_revenue l2 WHERE l1.month = l2.month In der obigen Abfrage definieren wir zwei CTEs, london1_monthly_revenue und london2_monthly_revenueum die monatlichen Einnahmen im Jahr 2021 für jede Filiale in London zu erhalten. Schließlich verbinden wir beide CTEs mit der Monatsspalte und berechnen den Gesamtumsatz für London, indem wir die Umsätze der beiden Filialen addieren. Das Ergebnis der Abfrage sehen Sie unten: monthlondon_revenuelondon1_revenuelondon2_revenue 121055815240 Im folgenden Beispiel erhalten wir einen Bericht, der jede Filiale über das Datum, an dem das größte Ticket (d. h. die Menge der Artikel-Mengen-Kombination) verkauft wurde, und den Betrag dieses Tickets informiert. Zu diesem Zweck müssen wir eine CTE erstellen, die die Tickets (die Spalte position ist die Rangfolge) für jede Filiale nach dem Ticketbetrag ordnet. WITH tickets AS ( SELECT distinct branch, date, unit_price * quantity AS ticket_amount, ROW_NUMBER() OVER ( PARTITION BY branch ORDER by unit_price * quantity DESC ) AS position FROM sales ORDER BY 3 DESC ) SELECT branch, date, ticket_amount FROM tickets WHERE position =1 In der obigen Abfrage erstellen wir eine CTE mit den Spalten branch, date, ticket_amount und position. In der äußeren Abfrage filtern wir dann nur nach den Datensätzen mit position = 1, um das zu erhalten, was wir wollen, nämlich das größte Ticket nach Zweigstelle. Das Ergebnis der Abfrage ist unten dargestellt: branchdateticket_amount London-12021-11-2450 London-22021-11-1270 Paris-12021-12-780 Verschachtelte CTEs in SQL-Abfragen Das nächste Beispiel zeigt eine verschachtelte CTE. Die Idee ist, einen Bericht mit allen Artikeln zu erstellen, deren Preis über 90 $ liegt, sowie die Menge dieser Artikel, die von der Filiale London-2 verkauft wurden. WITH over_90_items AS ( SELECT DISTINCT item, unit_price FROM sales WHERE unit_price >=90 ), london2_over_90 AS ( SELECT o90.item, o90.unit_price, coalesce(SUM(s.quantity), 0) as total_sold FROM over_90_items o90 LEFT JOIN sales s ON o90.item = s.item AND s.branch = 'London-2' GROUP BY o90.item, o90.unit_price ) SELECT item, unit_price, total_sold FROM london2_over_90; Die erste CTE lautet over_90_itemsdie alle Artikel auswählt, deren Preis größer als oder gleich 90 $ ist. Das zweite CTE ist london2_over_90mit der die von London-2 verkaufte Menge für jeden Artikel in over_90_items. Diese Abfrage hat eine verschachtelte CTE - beachten Sie die FROM in der zweiten CTE, die sich auf die erste bezieht. Wir verwenden LEFT JOIN sales, weil London-2 möglicherweise nicht jeden Artikel in over_90_items. Das Ergebnis der Abfrage ist: itemunit_pricetotal_sold Cell Phone X11000 Cell Phone X21200 Cell Phone B2907 Bevor wir zum nächsten Abschnitt kommen, möchte ich Ihnen einige Artikel über allgemeine Tabellenausdrücke empfehlen. Sowohl "SQL CTEs Explained with Examples" als auch "Where Can I Find Good SQL CTE Exercises?" enthalten eine Menge Beispiele und Übungen. Rekursive Abfragen und Gemeinsame Tabellenausdrücke In relationalen Datenbanken ist es üblich, Tabellen zu haben, die Datenhierarchien wie Mitarbeiter-Manager, Teil-Teil oder Eltern-Kind darstellen. Um diese Hierarchien in beliebiger Richtung zu durchlaufen (von oben nach unten oder von unten nach oben), verwenden Datenbanken ein Konstrukt namens rekursive CTEs. RECURSIVE ist ein reserviertes Wort zur Definition eines CTE für die Durchquerung einer rekursiven Datenstruktur. Die Form der rekursiven Abfrage ist wie folgt: WITH RECURSIVE cte_name AS ( CTE_query_definition -- non recursive query term UNION ALL CTE_query_definition -- recursive query term ) SELECT * FROM cte_name; Rekursive Abfragen liegen außerhalb des Rahmens dieses Einführungsartikels, aber ich empfehle drei weitere Artikel für diejenigen, die mehr über dieses Thema erfahren möchten: "How to Organize SQL Queries with CTEs", "Doit in SQL": Rekursives SQL Tree Traversal" und "LernenSie die Leistungsfähigkeit von SQL kennen Rekursive Abfragen." Sie erklären rekursive Abfragen im Detail mit vielen Beispielen. SQL CTEs sind eine mächtige Ressource Gemeinsame Tabellenausdrücke sind eine mächtige Ressource der SQL-Sprache. Mit ihnen lassen sich besser lesbare Abfragen erstellen und Formatunterschiede zwischen Tabellen- und Berichtsdaten verwalten. In diesem Artikel haben wir uns damit beschäftigt, was ein CTE ist und wie man sie in verschiedenen Abfragetypen verwendet. Wir haben auch erwähnt, dass CTEs in rekursiven Abfragen verwendet werden können. Ich empfehle den Kurs Rekursive Abfragen auf LearnSQL.dein dem Sie interaktiv lernen, wie man mit allgemeinen Tabellenausdrücken in SQL arbeitet. Sie lernen auch, wie Sie rekursive Datenstrukturen wie Graphen und Bäume in SQL mit rekursiven CTEs verarbeiten können. Besuchen Sie auch den Track Fortgeschrittenes SQLan, in dem Sie über die Grundlagen hinausgehen, um ein SQL-Meister zu werden. Wenn Sie sich auf ein SQL-Interview vorbereiten müssen, gibt es einen interessanten Artikel "Top 5 SQL CTE Interview Questions", in dem gängige Tabellenausdrücke aus einer anderen Perspektive betrachtet werden. Wenn Sie gelernt haben, wie man CTEs verwendet, sind Sie auf dem Weg zum SQL-Entwickler schon einen Schritt weiter. Wachsen Sie weiter! Tags: CTE