Zurück zur Artikelliste Artikel
11 Leseminuten

5 praktische Beispiele für die WITH-Klausel von SQL

Diese fünf praktischen Anwendungsfälle werden Sie dazu veranlassen, die SQL WITH-Klausel täglich zu verwenden .

Die WITH Klausel kann Ihnen helfen, lesbare SQL-Abfragen zu schreiben und komplexe Berechnungen in logische Schritte zu unterteilen. Sie wurde zu SQL hinzugefügt, um komplizierte lange Abfragen zu vereinfachen. In diesem Artikel zeigen wir Ihnen 5 praktische Beispiele für die WITH Klausel und erklären Ihnen, wie Sie mit ihr SQL-Abfragen lesbarer machen können.

Die WITH Klausel wird auch als Common Table Expression (CTE) bezeichnet. Der Umgang damit gehört nicht zu den SQL-Grundkenntnissen, daher empfehlen wir, WITH in einem strukturierten interaktiven Kurs zu üben, z. B. in unserem Rekursive Abfragen Kurs. In über 100 Übungen lernen Sie die grundlegende Syntax von CTEs sowie die fortgeschrittenen Konzepte von verschachtelten und rekursiven CTEs.

Was ist die WITH-Klausel in SQL?

Der andere Name der WITH Klausel, Common Table Expression, gibt einen Hinweis darauf, was sie tut. Mit einer WITH -Klausel können Sie eine SELECT -Anweisung erstellen, die ein temporäres Ergebnis zurückgibt; Sie können dieses Ergebnis benennen und in einer anderen Abfrage darauf verweisen. Im Grunde handelt es sich um eine benannte Unterabfrage, die jedoch rekursiv sein kann. Im Folgenden wird eine WITH-Klausel mit einer Unterabfrage verglichen.

Die CTE kann nicht ohne die Hauptabfrage ausgeführt werden, daher muss ihr eine reguläre Abfrage folgen. Diese Abfrage ist in der Regel ebenfalls eine SELECT-Anweisung, kann aber INSERT, UPDATE oder DELETE lauten.

Stellen Sie sich eine CTE als eine temporäre Tabelle mit einer Abfrage vor, die immer ausgeführt werden muss, damit die Tabelle verwendet werden kann. Da es sich um eine Art von Tabelle handelt, können Sie in der FROM -Klausel auf die CTE wie auf eine normale Tabelle verweisen.

Grundlegende WITH-Klausel-Syntax

Was wir oben erklärt haben, kann als SQL-Code dargestellt werden:

WITH cte AS (
  SELECT …
  FROM table
)

SELECT …
FROM cte;

Werfen wir einen Blick auf die wichtigsten Teile der Syntax. Der CTE wird immer, ohne Ausnahme, durch die WITH Klausel eingeleitet. Danach folgt der CTE-Name, der im obigen generischen Beispiel cte lautet. Nach dem CTE-Namen folgt das Schlüsselwort AS. Was in den Klammern folgt, ist die Definition des CTE. In einem sehr einfachen Beispiel ist dies nur eine SELECT Anweisung. Schließlich folgt die Hauptabfrage (wie bei normalen Unterabfragen), die auf das CTE verweist.

Wohlgemerkt, das ist die grundlegende Syntax. Wir werden sie in den Beispielen wieder aufgreifen. Dabei werden Sie auch sehen, wie diese grundlegende Syntax durch das Schreiben mehrerer oder verschachtelter CTEs erweitert werden kann.

Beispiele 1 und 2: Gehaltsinformationen

Beispiel Daten

Wir verwenden die Tabelle employees in den ersten beiden Beispielen. Sie hat die folgenden Spalten:

  • id - Die ID des Mitarbeiters.
  • first_name - Der Vorname des Mitarbeiters.
  • last_name - Der Nachname des Mitarbeiters.
  • salary - Das Gehalt des Mitarbeiters.
  • department - Die Abteilung des Angestellten.

Hier sind die Daten:

idfirst_namelast_namesalarydepartment
1MelissaAllman5,412.47Accounting
2NinaLonghetti4,125.79Controlling
3SteveClemence3,157.99Accounting
4JohnSample5,978.15Controlling
5CaroleCharles6,897.47Accounting
6EttaCobham4,579.55Controlling
7JamesJohnson4,455.66Accounting
8VictorHooper6,487.47Controlling
9BettyeJames4,597.88Accounting
10SusanTrucks5,497.45Controlling

Und hier ist ein Link zu einer Abfrage, die Sie ausführen können, um die Tabelle zu erstellen:

Beispiel 1: Zeigen Sie, wie das Gehalt jedes Mitarbeiters im Vergleich zum Durchschnitt des Unternehmens ist

Um diese Aufgabe zu lösen, müssen Sie alle Daten der Tabelle anzeigen employees. Außerdem müssen Sie das Durchschnittsgehalt des Unternehmens und dann die Differenz zu den Gehältern der einzelnen Mitarbeiter anzeigen.

Hier ist die Lösung:

WITH avg_total_salary AS (
	SELECT AVG(salary) AS average_company_salary
	FROM employees
)
	
SELECT id,
	 first_name,
	 last_name,
	 salary,
	 department,
	 average_company_salary,
	 salary - average_company_salary  AS salary_difference
FROM employees, avg_total_salary;

Starten Sie zunächst die CTE mit der Klausel WITH. Der Name der CTE ("avg_total_salary") kommt danach. Öffnen Sie die Klammern nach AS, und schreiben Sie die reguläre Anweisung SELECT. Sie berechnet das Durchschnittsgehalt des Unternehmens.

Um die CTE-Ausgabe zu verwenden, schreiben Sie eine weitere SELECT -Anweisung als Hauptabfrage. Beachten Sie, dass die CTE und die Hauptabfrage nur durch Klammern getrennt sind. Die neue Zeile dient nur der besseren Lesbarkeit. Die Hauptabfrage wählt alle Spalten sowohl aus der Tabelle als auch aus dem CTE aus. Die CTE und die Tabelle employees werden wie zwei normale Tabellen miteinander verbunden. Zusätzlich gibt es die berechnete Spalte salary_difference.

Die Abfrage gibt dies zurück:

idfirst_namelast_namesalarydepartmentaverage_company_salarysalary_difference
1MelissaAllman5,412.47Accounting5,118.99293.48
2NinaLonghetti4,125.79Controlling5,118.99-993.20
3SteveClemence3,157.99Accounting5,118.99-1,961.00
4JohnSample5,978.15Controlling5,118.99859.16
5CaroleCharles6,897.47Accounting5,118.991,778.48
6EttaCobham4,579.55Controlling5,118.99-539.44
7JamesJohnson4,455.66Accounting5,118.99-663.33
8VictorHooper6,487.47Controlling5,118.991,368.48
9BettyeJames4,597.88Accounting5,118.99-521.11
10SusanTrucks5,497.45Controlling5,118.99378.46

Wir können die Daten aller Mitarbeiter sehen und um wie viel ihr Gehalt über oder unter dem Unternehmensdurchschnitt liegt. Zum Beispiel liegt das Gehalt von Melissa Allman um 293,48 höher als der Durchschnitt. Das Gehalt von Nina Longhetti liegt 993,20 unter dem Durchschnitt.

Beispiel 2: Zeigen Sie die Daten der Mitarbeiter zusammen mit dem durchschnittlichen Abteilungs- und dem durchschnittlichen Unternehmensgehalt an

Gehen wir noch ein wenig weiter als im vorherigen Beispiel. Diesmal müssen Sie nicht die Differenz zwischen den Gehältern berechnen. Aber Sie müssen die analytischen Daten aller Mitarbeiter anzeigen und dann das durchschnittliche Abteilungs- und Firmengehalt.

Dies können Sie erreichen, indem Sie zwei CTEs statt einer schreiben:

WITH avg_total_salary AS (
	SELECT AVG(salary) AS average_company_salary
	FROM employees
),
	
avg_dpt_salary AS (
	SELECT department,
		 AVG(salary) AS average_department_salary
	FROM employees
	GROUP BY department
)
	
SELECT e.id,
	   e.first_name,
	   e.last_name,
	   e.salary,
	   average_department_salary,
	   average_company_salary
FROM employees e JOIN avg_dpt_salary ads ON e.department = ads.department, avg_total_salary;

Erinnern Sie sich, dass wir erwähnt haben, dass die Basissyntax erweitert werden kann. Hier ist ein Beispiel für diese Vorgehensweise. Ja, Sie können mehrere CTEs schreiben, eine nach der anderen, und dann in der Hauptabfrage auf sie verweisen.

Schauen wir uns an, wie man das macht. Bei der ersten CTE ist alles wie gewohnt: WITH-Klausel, der CTE-Name, AS und die CTE-Definition in Klammern. Diese CTE berechnet das Durchschnittsgehalt des Unternehmens.

Die zweite CTE berechnet das Durchschnittsgehalt nach Abteilung. Aber hier ist etwas anders! Beachten Sie zwei wichtige Dinge: Es gibt keine weitere WITH-Klausel, und die CTEs sind durch ein Komma getrennt.

So schreibt man mehrere CTEs: Die WITH-Klausel wird nur vor der ersten Abfrage geschrieben (sie darf vor keiner anderen CTE erscheinen!), und die CTEs müssen durch ein Komma getrennt werden.

Unabhängig von der Anzahl der CTEs muss ihnen immer die Hauptabfrage folgen. Und zwischen der letzten CTE und der Hauptabfrage steht kein Komma!

Die Hauptabfrage verknüpft die Tabelle mit den beiden CTEs und wählt die relevanten Daten aus. Die Verknüpfung erfolgt auf dieselbe Weise wie bei regulären Tabellen: Geben Sie die Art der Verknüpfung und die Spalte an, über die die Tabellen verknüpft werden sollen.

Hier ist die Ausgabe:

idfirst_namelast_namesalaryaverage_department_salaryaverage_company_salary
1MelissaAllman5,412.474,904.295,118.99
2NinaLonghetti4,125.795,333.685,118.99
3SteveClemence3,157.994,904.295,118.99
4JohnSample5,978.155,333.685,118.99
5CaroleCharles6,897.474,904.295,118.99
6EttaCobham4,579.555,333.685,118.99
7JamesJohnson4,455.664,904.295,118.99
8VictorHooper6,487.475,333.685,118.99
9BettyeJames4,597.884,904.295,118.99
10SusanTrucks5,497.455,333.685,118.99

Jetzt haben Sie alle Daten an einem Ort: individuelle Gehälter, Abteilungsdurchschnitt und Unternehmensdurchschnitt. Von hier aus können Sie Ihre Datenanalyse fortsetzen.

Beispiele 3 und 4: Umsatzerlöse

Beispiel Daten

In den nächsten beiden Beispielen werden wir die Tabelle revenue. Wir haben sie mit der Abfrage CREATE TABLE erstellt, die Sie hier finden. Sie hat die folgenden Spalten:

  • id - Die ID des Umsatzdatensatzes.
  • year - Das Jahr des Umsatzes.
  • quarter - Das Quartal der Einnahme.
  • revenue_amount - Der Betrag der Einnahme.

Machen Sie sich mit den unten gezeigten Daten vertraut:

idyearquarterrevenue_amount
12019Q11,589,745.56
22019Q22,497,845.41
32019Q3984,157.15
42019Q45,417,884.15
52020Q12,497,441.68
62020Q24,448,741.15
72020Q39,847,415.14
82020Q44,125,489.65
92021Q112,478,945.47
102021Q28,459,745.69
112021Q34,874,874.51
122021Q45,123,456.87
132022Q14,112,587.26
142022Q26,459,124.65
152022Q37,894,561.55

Beispiel 3: Jedes Jahr mit den entsprechenden Jahreseinnahmen und Gesamteinnahmen anzeigen

Verwenden Sie die obigen Daten, um alle verfügbaren Jahre anzuzeigen. Geben Sie zu jedem Jahr den Jahresumsatz und den Gesamtumsatz des Unternehmens in allen Jahren an.

Diese Aufgabe ist ähnlich wie in Beispiel 1, aber wir verwenden eine andere Aggregatfunktion:

WITH total_revenue AS (
	SELECT SUM(revenue_amount) AS total_company_revenue
	FROM revenue
)
	
SELECT year,
	 SUM (revenue_amount) AS annual_revenue,
	 total_company_revenue
FROM revenue, total_revenue
GROUP BY year, total_company_revenue
ORDER BY year;

Das CTE verwendet die Aggregatfunktion SUM(), um den Gesamtumsatz des Unternehmens zu berechnen.

Die Hauptabfrage verknüpft die CTE mit der Tabelle revenue. Wir verwenden diese SELECT Anweisung, um das Jahr anzuzeigen, dann die jährlichen Einnahmen für jedes Jahr zu berechnen und die Gesamteinnahmen anzuzeigen.

Dies ist die Ausgabe der Abfrage:

yearannual_revenuetotal_company_revenue
201910,489,632.2780,812,015.89
202020,919,087.6280,812,015.89
202130,937,022.5480,812,015.89
202218,466,273.4680,812,015.89

Das Ergebnis zeigt, dass der Jahresumsatz im Jahr 2019 10.489.632,27 betrug. Im Jahr 2020 waren es 20.919.087,62 und so weiter. Wenn man alle vier Jahre zusammenzählt, ergibt sich ein Gesamtumsatz von 80.812.015,89.

Beispiel 4: Auflistung der einzelnen Quartale mit den höchsten und niedrigsten Quartalseinnahmen für das jeweilige Jahr und insgesamt

Sie müssen alle Jahre und Quartale mit den entsprechenden Einnahmen auflisten. So weit, so gut. Dann müssen Sie den niedrigsten Quartalsumsatz für dieses Jahr und den niedrigsten Quartalsumsatz für alle Jahre angeben. Als nächstes machen Sie das Gleiche für den höchsten Umsatz.

Hier ist die Lösung:

WITH yearly_min_max_quarter AS (
	SELECT year,
		   MIN(revenue_amount) AS minimum_quarterly_revenue_annual,
		   MAX(revenue_amount) AS maximum_quarterly_revenue_annual
FROM revenue
GROUP BY year),

min_max_overall AS (
	SELECT MIN(revenue_amount) AS overall_min_revenue,
	       MAX(revenue_amount) AS overall_max_revenue
FROM revenue)

SELECT r.year,
	   quarter,
	   revenue_amount,
	   minimum_quarterly_revenue_annual,
	   overall_min_revenue,
	   maximum_quarterly_revenue_annual, 
	   overall_max_revenue
FROM revenue r 
JOIN yearly_min_max_quarter ymmq 
ON r.year = ymmq.year, min_max_overall
ORDER BY year, quarter ASC;

Auch für diese Lösung sind zwei CTEs erforderlich. Wahrscheinlich wissen Sie bereits, wie man sie schreibt, aber lassen Sie uns die einzelnen Schritte erklären.

Die erste CTE ermittelt die niedrigsten und höchsten Quartalsumsätze für jedes Jahr. Verwenden Sie dazu die Funktionen MIN() und MAX() und gruppieren Sie die Daten nach Jahr.

Schreiben Sie dann die zweite CTE ohne die WITH Klausel und trennen Sie sie durch ein Komma von der ersten. Diese CTE gibt den niedrigsten und den höchsten Quartalsumsatz in allen Jahren zurück.

Die Hauptabfrage verknüpft die Tabelle revenue mit dem ersten und dann mit dem zweiten CTE. Sie zeigt die Daten aus der Tabelle und dem CTE als eine Tabelle an.

Werfen Sie einen Blick auf das Ergebnis:

yearquarterrevenue_amountminimum_quarterly_revenue_annualoverall_min_revenuemaximum_quarterly_revenue_annualoverall_max_revenue
2019Q11,589,745.56984,157.15984,157.155,417,884.1512,478,945.47
2019Q22,497,845.41984,157.15984,157.155,417,884.1512,478,945.47
2019Q3984,157.15984,157.15984,157.155,417,884.1512,478,945.47
2019Q45,417,884.15984,157.15984,157.155,417,884.1512,478,945.47
2020Q12,497,441.682,497,441.68984,157.159,847,415.1412,478,945.47
2020Q24,448,741.152,497,441.68984,157.159,847,415.1412,478,945.47
2020Q39,847,415.142,497,441.68984,157.159,847,415.1412,478,945.47
2020Q44,125,489.652,497,441.68984,157.159,847,415.1412,478,945.47
2021Q112,478,945.474,874,874.51984,157.1512,478,945.4712,478,945.47
2021Q28,459,745.694,874,874.51984,157.1512,478,945.4712,478,945.47
2021Q34,874,874.514,874,874.51984,157.1512,478,945.4712,478,945.47
2021Q45,123,456.874,874,874.51984,157.1512,478,945.4712,478,945.47
2022Q14,112,587.264,112,587.26984,157.157,894,561.5512,478,945.47
2022Q26,459,124.654,112,587.26984,157.157,894,561.5512,478,945.47
2022Q37,894,561.554,112,587.26984,157.157,894,561.5512,478,945.47

Zusammen mit den Einnahmen der einzelnen Quartale haben Sie nun einige weitere wichtige Informationen. Sie wissen, dass der niedrigste Umsatz im Jahr 2019 984.157,15 betrug, und Sie können sehen, dass dies im 3. Der niedrigste Umsatz im Jahr 2020 (2.497.441,68) wurde in den ersten drei Monaten des Jahres erzielt. Sie können alle anderen Jahre auf ähnliche Weise analysieren, indem Sie die Spalte minimum_quarterly_revenue_annual betrachten.

Der Wert in der Spalte overall_min_revenue stellt den niedrigsten Umsatz aller Zeiten dar. Er ist in allen Zeilen gleich und entspricht dem Jahr 2019Q3. Die nächsten beiden Spalten sind ähnlich, zeigen aber den höchsten statt den niedrigsten Umsatz an. Mit anderen Worten: Die höchsten Einnahmen im Jahr 2019 waren 5.417.884,15, die aus Q4 stammen. Der höchste Umsatz aller Zeiten ist 12.478.945,47, der im Jahr 2021Q1 erzielt wurde.

Beispiel 5: Geleistete Arbeitsstunden

Beispiel Daten

Die Tabelle für das letzte Beispiel heißt Mitarbeiter_Stundenzettel. Sie erfasst die Arbeitszeiten der Mitarbeiter. Ihre Spalten sind selbsterklärend, also schauen wir uns nur die Daten an:

idemployee_idstart_timeend_time
112022-10-01 11:25:562022-10-01 21:41:58
212022-10-01 17:37:422022-10-01 19:15:47
322022-10-02 4:38:142022-10-02 21:06:57
422022-10-05 18:13:372022-10-06 4:33:51
532022-10-07 11:36:232022-10-07 14:06:44
632022-10-08 11:24:482022-10-08 22:42:12

Beispiel 5: Die niedrigsten und höchsten durchschnittlichen Arbeitsstunden anzeigen

In diesem Beispiel sollen Sie zunächst die durchschnittlichen Arbeitsstunden pro Mitarbeiter ermitteln und dann nur den niedrigsten und den höchsten Durchschnitt ausgeben.

Hier ist der Code, um dieses Problem zu lösen:

WITH login_times AS (
SELECT 
id,
employee_id,
start_time,
end_time,
end_time - start_time AS working_hours
FROM employee_timesheet),

avg_login AS (
	SELECT 
employee_id,
AVG(working_hours) AS average_working_hours
FROM login_times
GROUP BY employee_id)

SELECT MIN(average_working_hours) AS min_average_working_hours,
	 MAX(average_working_hours) AS max_average_working_hours
FROM avg_login;

Auf den ersten Blick könnte dies wie eine beliebige Abfrage mit zwei CTEs aussehen. Schauen Sie genauer hin, und Sie werden sehen, dass es nicht so ist! Ja, es gibt zwei CTEs. Der Unterschied ist jedoch, dass die zweite CTE auf die erste verweist, was in den Beispielen 2 und 4 nicht der Fall war.

Dies nennt man eine verschachtelte CTE. Die erste CTE wird verwendet, um die Differenz zwischen dem Beginn und dem Ende der Anmeldung zu ermitteln; so erhalten Sie die Arbeitsstunden für jede Sitzung.

Da ein Mitarbeiter mehrere Sitzungen hat, müssen wir die durchschnittliche Sitzungsdauer ermitteln, d. h. die durchschnittlich geleisteten Arbeitsstunden. Zu diesem Zweck wird die zweite CTE verwendet. Von der Syntax her ist nichts Neues, außer dass der CTE in der FROM -Klausel auf den ersten CTE verweist.

In der Hauptabfrage führen wir dann eine so genannte mehrstufige Aggregation durch. Wir nehmen die durchschnittlichen Arbeitsstunden pro Mitarbeiter (Aggregation auf erster Ebene) und finden das Minimum und Maximum dieser Werte (Aggregation auf zweiter Ebene).

Hier ist das Ergebnis:

min_average_working_hoursmax_average_working_hours
5:57:0413:24:29

Das Ergebnis zeigt uns, dass die niedrigste durchschnittliche Arbeitszeit pro Arbeitnehmer 5 Stunden, 57 Minuten und 4 Sekunden beträgt. Der höchste Durchschnitt liegt bei 13:24:29.

Vorteile der SQL WITH-Klausel

Die fünf Beispiele, die wir Ihnen gezeigt haben, wurden sorgfältig ausgewählt, um die typische Verwendung und die Vorteile der WITH-Klausel zu verdeutlichen.

Der erste Vorteil wird deutlich, wenn Sie mehrere Berechnungsschritte haben, wie wir es in den obigen Beispielen gesehen haben. Mit der WITH -Klausel können Sie den Code gut organisieren und in logische Teile unterteilen.

Wenn die Berechnungen komplizierter werden, nimmt auch die Länge und Komplexität des Codes zu. Mit der WITH Klausel lässt sich das gut in den Griff bekommen. Die Codes in den obigen Beispielen mögen zwar lang erscheinen, aber sie würden deutlich länger (und weniger lesbar) werden, wenn wir Unterabfragen anstelle der WITH Klausel verwenden würden. Und wie Sie im letzten Beispiel gesehen haben, können Sie mit der WITH Klausel problemlos mehrstufige Aggregationen berechnen.

Ein weiterer Vorteil ist, dass Sie mit der WITH -Klausel rekursive Abfragen in SQL schreiben können, was eine ganz neue Welt von Möglichkeiten eröffnet.

Das Erlernen der WITH Klausel kann manchmal überwältigend sein, daher haben wir einen Leitfaden erstellt, der Ihnen helfen wird, Ihren Ansatz zu strukturieren. Viel Spaß beim Lernen, und wir sind sicher, dass die SQL WITH Klausel Ihre Bemühungen mehr als belohnen wird!