Zurück zur Artikelliste Artikel
12 Leseminuten

Die 5 wichtigsten SQL CTE-Interview-Fragen

Hier finden Sie fünf Fragen (und Lösungen!) zu CTEs, die Ihnen (wahrscheinlich) in einem Vorstellungsgespräch gestellt werden.

Ich behaupte nicht, dass Sie diese SQL-CTE-Fragen in jedem Vorstellungsgespräch gestellt bekommen werden. Aber wenn Sie sie bekommen, dann sind sie wahrscheinlich ähnlich wie die fünf, die ich hier vorstelle.

Abgesehen von theoretischen Fragen zu CTEs gibt es nicht viele Variationen bei den CTE-Szenarien, die von den Interviewern bewertet werden. Wenn Sie diese fünf Beispiele durchgehen, erhalten Sie eine gute Grundlage für ein erfolgreiches Vorstellungsgespräch!

Hierfür müssen Sie wissen, was SQL Common Table Expressions sind und wie ihre Syntax funktioniert.

Sind Sie bereit, einen Blick auf die Fragen zu werfen? Los geht's!

Tabelle für die Fragen 1, 2 und 3

Für die erste Gruppe von Fragen verwenden wir die Tabelle employees. So sieht sie aus:

idfirst_namelast_namedepartmentsalarymanager_id
1AngelikaVoulesMarketing5,293.742
2RozelleSwynleyMarketing8,295.0818
3WarrenWilleyEngineering9,126.7219
4LynelleWhitenManagement Board10,716.15NULL
5ConsolataRomanLegal8,456.064
6HoebartBaldockResearch and Development4,817.3420
7StarleneWatkissAccounting6,541.484
8BardeRibbensMarketing4,852.872
9LornePhilipsenEngineering7,235.593
10PedroNaldrettResearch and Development5,471.6220
11BrinaDillingerMarketing6,512.172
12VerileSonleyResearch and Development4,574.4120
13NobleGeerlingResearch and Development8,391.1820
14GareyMacAdamAccounting3,829.887
15TheoSorrellEngineering6,441.673
16ErminieGellingResearch and Development8,590.7020
17LoralieKoopAccounting5,248.467
18CalAndreyManagement Board11,258.82NULL
19QuinceyGamellManagement Board11,366.52NULL
20JanithMcGiffieResearch and Development7,428.8319

Was sagen Ihnen die Daten? In der ersten Zeile steht zum Beispiel, dass Angelika Voules im Marketing arbeitet und ihr Gehalt 5.293,74 beträgt. Ihr Vorgesetzter hat eine Manager-ID von 2. Schauen Sie in der Spalte id nach, und Sie sehen, dass Angelika Voules Vorgesetzter Rozelle Swynley ist.

Es gibt drei Zeilen mit NULL-Werten in der Spalte manager_id:

idfirst_namelast_namedepartmentsalarymanager_id
4LynelleWhitenManagement Board10,716.15NULL
18CalAndreyManagement Board11,258.82NULL
19QuinceyGamellManagement Board11,366.52NULL

Es bedeutet, dass diese drei employees haben keine Manager. Das macht Sinn, da alle drei im Vorstand sind.

Schauen wir uns nun die Interviewfragen an.

Interviewfrage 1: Ermitteln Sie das Durchschnittsgehalt nach Abteilung

Zeigen Sie anhand der Tabelle Mitarbeiter alle Mitarbeiter, ihre Abteilungen, Gehälter und das Durchschnittsgehalt in ihrer jeweiligen Abteilung. Ordnen Sie das Ergebnis nach Abteilung.

Lösung Abfrage

WITH avg_salary AS (
		SELECT	AVG(salary) AS average_salary,
				department
		FROM employees
		GROUP BY department)
		
SELECT	e.first_name,
		e.last_name,
		e.department,
		e.salary,
		avgs.average_salary	
FROM employees e
JOIN avg_salary avgs
ON e.department = avgs.department
ORDER BY department;

Lösung Abfrage Erläuterung

Diese Abfrage verwendet ein CTE namens avg_salary um das Durchschnittsgehalt nach Abteilung zu berechnen. Die Anweisung SELECT in der CTE gruppiert die Zeilen nach Abteilung und verwendet die Aggregatfunktion AVG(), um den Durchschnitt für jede Abteilung zu berechnen.

Sobald wir das Ergebnis haben, kombinieren wir es mit anderen Spalten aus der Tabelle employees um die Antwort auf die Interviewfrage zu vervollständigen. Zu diesem Zweck verknüpfen wir die Tabelle employees mit dem CTE, wie wir es mit zwei beliebigen Tabellen tun würden. Wir wählen die Spalten first_name, last_name, department, und salary aus der Tabelle employeesund die Spalte average_salary aus der CTE. Der Einfachheit halber verwenden wir Aliasnamen für die Tabelle und die CTE. Schließlich ordnen wir das Ergebnis nach Abteilung.

Die Ergebnistabelle

So sieht das Ergebnis aus:

first_namelast_namedepartmentsalaryaverage_salary
GareyMacAdamAccounting3,829.885,206.61
LoralieKoopAccounting5,248.465,206.61
StarleneWatkissAccounting6,541.485,206.61
WarrenWilleyEngineering9,126.727,601.33
LornePhilipsenEngineering7,235.597,601.33
TheoSorrellEngineering6,441.677,601.33
ConsolataRomanLegal8,456.068,456.06
CalAndreyManagement Board11,258.8211,113.83
QuinceyGamellManagement Board11,366.5211,113.83
LynelleWhitenManagement Board10,716.1511,113.83
AngelikaVoulesMarketing5,293.746,238.47
RozelleSwynleyMarketing8,295.086,238.47
BardeRibbensMarketing4,852.876,238.47
BrinaDillingerMarketing6,512.176,238.47
NobleGeerlingResearch and Development8,391.186,545.68
ErminieGellingResearch and Development8,590.706,545.68
VerileSonleyResearch and Development4,574.416,545.68
PedroNaldrettResearch and Development5,471.626,545.68
HoebartBaldockResearch and Development4,817.346,545.68
JanithMcGiffieResearch and Development7,428.836,545.68

Das Ergebnis Erläuterung

Aus dieser Tabelle geht hervor, dass das Gehalt von Starlene Watkiss beispielsweise 6.541,48 beträgt und das Durchschnittsgehalt in ihrer Abteilung (Buchhaltung) bei 5.206,61 liegt.

first_namelast_namedepartmentsalaryaverage_salary
StarleneWatkissAccounting6,541.485,206.61

Sie können die übrigen Zeilen des Ergebnisses auf die gleiche Weise interpretieren.

Interviewfrage 2: Ermitteln des höchsten Gehalts nach Abteilung

Finden Sie den Mitarbeiter mit dem höchsten Gehalt in jeder Abteilung. Geben Sie den Vor- und Nachnamen, das Gehalt und die Abteilung an.

Lösung Abfrage

WITH highest_salary AS (
		SELECT	first_name,
				last_name,
				department,
				salary,
				RANK () OVER (PARTITION BY department ORDER BY salary DESC) AS salary_rank
		FROM employees)

SELECT	first_name,
		last_name,
		salary,
		department
FROM highest_salary
WHERE salary_rank = 1;

Lösung Abfrage Erläuterung

Dieses Mal heißt die CTE highest_salary. Wir verwenden sie, um die Mitarbeiter innerhalb jeder Abteilung nach ihrem Gehalt zu ordnen. Und wie? Indem wir die Fensterfunktion RANK() verwenden.

Wir partitionieren die Daten nach der Spalte Abteilung. Das bedeutet, dass wir die Gehälter nur innerhalb der einzelnen Abteilungen und nicht für das gesamte Unternehmen auflisten. Die Daten werden nach der Spalte Gehalt in absteigender Reihenfolge sortiert, da wir wollen, dass die höchste salary in der Abteilung den Rang 1 hat.

Wir wählen auch mehrere Spalten aus der Tabelle employees in der gleichen CTE. Wir benötigen die Daten aus dieser CTE in der nächsten Anweisung SELECT.

Und in der Anweisung SELECT wählen wir die Spalten aus, die für die Beantwortung der Interviewfrage benötigt werden. Alle Spalten stammen aus der CTE. Wir filtern das Ergebnis mit einer WHERE Klausel, um nur die Zeilen zu erhalten, deren Gehaltsrang 1 ist, d.h. die Zeilen mit dem höchsten Gehalt.

Die Ergebnistabelle

first_namelast_namesalarydepartment
StarleneWatkiss6,541.48Accounting
WarrenWilley9,126.72Engineering
ConsolataRoman8,456.06Legal
QuinceyGamell11,366.52Management Board
RozelleSwynley8,295.08Marketing
ErminieGelling8,590.70Research and Development

Das Ergebnis Erläuterung

Es ist nicht allzu schwierig, das Ergebnis zu interpretieren. Nehmen wir diesen Mitarbeiter als Beispiel:

first_namelast_namesalarydepartment
ConsolataRoman8,456.06Legal

Die angezeigten Daten zeigen, dass Consolata Roman mit 8.456,06 das höchste Gehalt in der Rechtsabteilung bezieht.

Kommen wir nun zur dritten SQL CTE-Interviewfrage.

Interviewfrage 3: Alle Mitarbeiter unter einem bestimmten Manager finden

Finden Sie alle Mitarbeiter, die direkt oder indirekt unter dem Mitarbeiter mit der ID 18 arbeiten.

Lösung Abfrage

WITH RECURSIVE subordinates AS (
		SELECT	id,
				first_name,
				last_name,
				manager_id
		FROM employees
		WHERE id = 18

	UNION

		SELECT	e.id,
				e.first_name,
				e.last_name,
				e.manager_id
		FROM employees e
JOIN subordinates s
ON e.manager_id = s.id
)
		
SELECT *
FROM subordinates
WHERE id != 18;

Erläuterung der Lösungsabfrage

In diesem Beispiel handelt es sich nicht um eine normale CTE, sondern wir verwenden eine rekursive CTE, um das Ergebnis zu erhalten. Der Unterschied in der Syntax ist WITH RECURSIVE statt nur WITH. Die CTE heißt subordinatesund dann kommt die Anweisung SELECT, genau wie bei nicht rekursiven CTEs.

Diese Anweisung wählt bestimmte Spalten aus der Tabelle aus employees aber nur für den Angestellten, dessen ID 18 ist. Dann verwenden wir den Operator UNION, um das Ergebnis dieser Anweisung SELECT mit dem Ergebnis einer anderen Anweisung SELECT zu verknüpfen. Dazu müssen beide SELECT-Anweisungen die gleichen Spalten haben.

Die zweite SELECT -Anweisung im CTE selektiert Spalten, bei denen manager_id (aus der Tabelle employees) gleich der id (aus der CTE) ist.

Wir erhalten alle Daten für den Mitarbeiter mit der ID 18. Dann suchen wir die direkten Untergebenen und durch Rekursion die Untergebenen der Untergebenen, bis wir die gesamte Hierarchie der Organisation durchlaufen haben.

Dann holen wir die Spalten aus dem CTE Untergebene und entfernen den Mitarbeiter mit der ID 18. Das war's!

Die Ergebnistabelle

idfirst_namelast_namemanager_id
2RozelleSwynley18
1AngelikaVoules2
8BardeRibbens2
11BrinaDillinger2

Die Erläuterung der Ergebnisse

Rozelle Swynleys direkter Vorgesetzter ist der Mitarbeiter, dessen Vorgesetzten-ID die 18 ist. Aber Rozelle hat auch Untergebene. Diese sind Angelika Voules, Barde Ribbens und Brina Dillinger. Das wissen wir, weil die Tabelle zeigt, dass die ID ihres Vorgesetzten 2 ist, was Rozelle Swynleys ID ist. Sie sind Rozelle Swynleys direkte Untergebene; sie sind auch indirekte Untergebene des Mitarbeiters mit der ID 18. Der Mitarbeiter mit der ID 18 ist Cal Andrey, der im Ergebnis nicht angezeigt wird, weil wir ihn in der Klausel WHERE herausfiltern.

Für die Fragen 4 und 5 verwendete Tabellen

Für die letzten beiden Interviewfragen verwenden wir die Tabellen customers und orders.

Die Tabelle customers sieht wie folgt aus:

idfirst_namelast_name
1SimonPaulson
2DylanBobson
3RebMackennack

Die Tabelle orders Tabelle ist ein bisschen größer:

idorder_dateorder_amountcustomer_id
12021-10-0142.123
22021-10-01415.631
32021-10-0284.992
42021-10-0228.963
52021-10-0254.311
62021-10-0374.261
72021-10-0377.772
82021-10-0355.703
92021-10-0416.943
102021-10-0451.441
112021-10-0541.583
122021-10-0695.001

Diese zweite Tabelle enthält Daten über die erteilten Aufträge. Die Spalte customer_id ist ein Fremdschlüssel zum Primärschlüssel der ersten Tabelle, so dass wir feststellen können, welcher Kunde welche Bestellung aufgegeben hat. Nehmen wir die erste Zeile als Beispiel:

idorder_dateorder_amountcustomer_id
12021-10-0142.123

Es handelt sich um eine Bestellung, die am 1. Oktober 2021 aufgegeben wurde. Der Wert der bestellten Waren beträgt 42,12, und die Bestellung wurde von einem Kunden mit der ID 3 aufgegeben. Aus der Tabelle customerssehen Sie, dass es sich um Reb Mackennack handelt.

Sehen wir uns die Aufgaben an, die mit diesen Tabellen zu lösen sind.

Interviewfrage 4: Finden Sie die durchschnittliche Anzahl der Bestellungen

In dieser Interviewfrage werden Sie gebeten, einen allgemeinen SQL-Tabellenausdruck zu verwenden, um die durchschnittliche Anzahl der Bestellungen pro Kunde zu ermitteln.

Lösung Abfrage

WITH orders_count AS (
		SELECT	customer_id,
				COUNT(*) AS no_of_orders
		FROM orders
		GROUP BY customer_id)

SELECT	AVG(no_of_orders) AS avg_no_of_orders
FROM orders_count;

Lösung Abfrage Erläuterung

Um das Ergebnis zu erhalten, zählen Sie zunächst die Anzahl der Bestellungen pro Kunde. Dies geschieht mit Hilfe der CTE orders_count und der darin enthaltenen Funktion COUNT(). Diese Funktion zählt die Anzahl der Zeilen in der Tabelle orders. Da wir nicht an der Gesamtzahl der Bestellungen, sondern an der Anzahl der Bestellungen pro Kunde interessiert sind, gruppiere ich das Ergebnis nach der Spalte customer_id.

Da wir nun die Anzahl der Bestellungen haben, ist es einfach, die durchschnittliche Anzahl zu berechnen. Verwenden Sie einfach die Funktion AVG() in der Anweisung SELECT, und Sie erhalten die Antwort auf die Interviewfrage.

Die Ergebnistabelle

avg_no_of_orders
4

Die Erläuterung der Ergebnisse

Eine sehr kleine Tabelle erfordert eine sehr kurze Erklärung. Die obige Tabelle zeigt einfach, dass die durchschnittliche Anzahl der Bestellungen pro Kunde vier beträgt.

Interviewfrage 5: Finden Sie die Anzahl der aufeinanderfolgenden Tage mit Bestellung

In diesem CTE-Beispiel müssen Sie berechnen, an wie vielen Tagen in Folge jeder Kunde eine Bestellung aufgibt. Im Grunde sollen Sie die Länge einer zusammenhängenden Reihe ohne Lücken berechnen. Beachten Sie, dass alle Bestellungen innerhalb desselben Monats liegen.

Lösung Abfrage

WITH groupings_by_date AS (
	SELECT	c.id,
			c.first_name,
			c.last_name,
			RANK() OVER (PARTITION BY c.id ORDER BY o.order_date) AS row_number,
			o.order_date,
			EXTRACT(DAY FROM o.order_date) - RANK() OVER (PARTITION BY c.id ORDER BY o.order_date) AS date_group
FROM customers c
JOIN orders o
ON c.id = o.customer_id
)

SELECT	id,
		first_name,
		last_name,
		COUNT(*) AS orders_in_row
FROM groupings_by_date
GROUP BY id, first_name, last_name, date_group;

Erläuterung zur Lösungsabfrage

Diese recht langwierige Abfrage beginnt mit einer CTE. Sie wählt bestimmte Spalten aus den Tabellen customers und orders. Es gibt eine RANK() Fensterfunktion wie in Frage 2. Diesmal verwenden wir diese Funktion, um jeder Bestellung innerhalb desselben Kunden eine Zeilennummer zuzuordnen. Aus diesem Grund partitionieren wir die Daten nach der Spalte id. Die Reihung erfolgt nach dem Bestelldatum (wir wollen, dass die Reihung sequentiell ist).

Die andere Funktion, die hier verwendet wird, ist EXTRACT(). Ihr Zweck ist es, den Tagesanteil aus dem Bestelldatum zu extrahieren, damit wir die Zeilennummer davon abziehen können.

Warum tun wir das? Wir geben einer Gruppe von aufeinanderfolgenden Bestellungen einfach eine gemeinsame date_group. Wenn Sie nur diese CTE ausführen, sehen die ersten beiden Zeilen des Ergebnisses wie folgt aus:

idfirst_namelast_namerow_numberorder_datedate_group
1SimonPaulson12021-10-010
1SimonPaulson22021-10-020

Wie Sie sehen können, hat Simon Paulson sowohl am 1. Oktober als auch am 2. Oktober 2021 Aufträge erteilt. Da sie an zwei aufeinanderfolgenden Tagen platziert wurden, gehören sie zu derselben date_group.

Wie kommen wir zu diesem Wert? Es ist der Tag, der aus der order_date minus der row_number extrahiert wurde.

In der ersten Zeile ist der Tag des Datums "2021-10-01" gleich 1. Die Zeilennummer ist ebenfalls 1. Es ist also 1-1 = 0, was auch der Wert in date_group ist. Die zweite Zeile ist 2-2 = 0, was dem Wert von date_group entspricht.

Der spezifische Wert von date_group ist nicht wirklich wichtig! Wichtig ist nur, dass die aufeinanderfolgenden Tage den gleichen date_group Wert haben. Dies ist ein kleiner Trick, um die Länge einer Serie zu berechnen. Er funktioniert, weil die Differenz zwischen der Anzahl der Tage in order_date und dem Wert in row_number für ein und denselben Kunden immer gleich ist, wenn die Bestellungen jeden Tag erfolgen.

Beachten Sie, dass diese Daten nirgendwo erscheinen. Ich zeige sie Ihnen nur, um Ihnen zu verdeutlichen, was die CTE hier tut.

Es ist wichtig zu erwähnen, dass dieser Trick nur funktioniert, wenn Ihre Daten alle im selben Monat liegen. Wenn die Reihe z. B. am 2021-10-31 beginnt und bis zum 2021-11-01 geht, funktioniert der Trick nicht; diese beiden Tage, obwohl sie hintereinander liegen, gehören nicht zum selben date_group. Sie müssen also Ihre Daten verstehen, bevor Sie diesen Trick anwenden, um die Länge einer Reihe zu bestimmen.

Sobald Sie das CTE haben, verwenden Sie es wie eine Tabelle in der Anweisung SELECT. Ich werde die Funktion COUNT() verwenden, um die Anzahl der Bestellungen in einer Zeile zu ermitteln. Da ich das Ergebnis für jeden Kunden sehen möchte, gruppiere ich die Daten nach id, first_name und last_name. Außerdem gruppiere ich sie nach der Spalte date_group, so dass die Bestellungen desselben Kunden getrennt werden, wenn eine Lücke zwischen ihnen besteht.

Die Ergebnistabelle

idfirst_namelast_nameorders_in_row
1SimonPaulson4
3RebMackennack5
2DylanBobson2
1SimonPaulson1

Das Ergebnis Erläuterung

Diese Tabelle zeigt, dass Simon Paulson vier Bestellungen in Folge aufgegeben hat. Reb Mackennack hat dies fünf Tage in Folge getan, während Dylan Bobson nur zwei Bestellungen in Folge aufgegeben hat. Schließlich gibt es noch eine zusätzliche Bestellung von Simon Paulson.

Wann sind CTEs nützlich?

Wie Sie in diesen Beispielen sehen, sind CTEs sehr nützlich, wenn Sie etwas in mindestens zwei Schritten berechnen müssen. Sie verwenden ein CTE, um die erste Berechnung vorzubereiten, und dann verwenden Sie einfach die Anweisung SELECT, verweisen auf das CTE und führen eine weitere Berechnungsstufe durch.

Bei komplexeren Berechnungen können Sie auch mehrere CTEs oder sogar verschachtelte CTEs verwenden. Das ist ähnlich wie bei Unterabfragen, aber CTEs machen den Code lesbarer und erleichtern die Aufgliederung der Berechnung in Schritte. Und mit verschachtelten CTEs können Sie eine Abfrage schreiben und sofort auf sie verweisen wie auf jede andere Tabelle.

Einige dieser Beispiele zeigen, dass Sie auch Aggregat- und Fensterfunktionen verwenden können. Dies macht CTEs noch leistungsfähiger.

Darüber hinaus eignen sich CTEs hervorragend für hierarchische Daten wie Organisationsstrukturen und zum Durchlaufen eines Graphen. Allerdings müssen Sie in diesen Fällen ein rekursives CTE schreiben, wie ich es in Frage 3 getan habe.

Wenn Sie rekursive Abfragen schreiben und verwenden möchten, müssen Sie zunächst CTEs lernen. Wenn Sie Hilfe brauchen, finden Sie hier einen Leitfaden zum Erlernen von CTEs.

Wie Sie sehen können, haben CTEs viele Vorteile und praktische Anwendungen. Diese Beispiele zeigen Ihnen nur einen kleinen Einblick in Lösungen für praktische Probleme, die ohne CTEs viel länger dauern würden. Sie wollen noch mehr? Kein Problem, schauen Sie sich einige andere praktische Anwendungen von CTEs an.

Wenn Sie CTEs gelernt haben und anfangen, sie zu verwenden, versuchen Sie, zuerst über das Problem nachzudenken. Brechen Sie die Berechnungsschritte auf und übersetzen Sie diese Logik dann in einen SQL-Code für einen gemeinsamen Tabellenausdruck. CTEs sind dafür geeignet.

Da es sich bei CTEs um eine Version von temporären Tabellen handelt, sollten Sie sie klar benennen: Verwenden Sie einen Namen, aus dem sofort hervorgeht, was die CTE tut, und halten Sie sich an die Namenskonventionen. Generell sollten Sie sich an die bewährten CTE-Verfahren halten, die Ihnen (und anderen!) das Lesen des Codes erheblich erleichtern.

Möchten Sie mehr über SQL Common Table Expressions wissen?

Egal, ob Sie sich auf ein SQL-Vorstellungsgespräch vorbereiten, in Ihrem derzeitigen Job besser werden wollen oder einfach in Ihrer Freizeit etwas Neues lernen möchten, werfen Sie einen Blick auf unseren Rekursive Abfragen Kurs an.

Dort finden Sie einen systematischen Ansatz für CTEs, der die Theorie dahinter erklärt, Ihnen die Syntax zeigt und Ihnen weitere Beispiele zum Üben gibt. Der gesamte Kurs ist Teil des Fortgeschrittenes SQL Track, der zwei weitere Themen abdeckt: Fensterfunktionen (die wir in diesem Artikel verwendet haben) und die GROUP BY Erweiterungen. Viel Erfolg!