23rd Jun 2022 12 Leseminuten Die 5 wichtigsten SQL CTE-Interview-Fragen Tihomir Babic CTE SQL-Interviewfragen Inhaltsverzeichnis Tabelle für die Fragen 1, 2 und 3 Interviewfrage 1: Ermitteln Sie das Durchschnittsgehalt nach Abteilung Lösung Abfrage Lösung Abfrage Erläuterung Die Ergebnistabelle Das Ergebnis Erläuterung Sie können die übrigen Zeilen des Ergebnisses auf die gleiche Weise interpretieren. Interviewfrage 2: Ermitteln des höchsten Gehalts nach Abteilung Lösung Abfrage Lösung Abfrage Erläuterung Die Ergebnistabelle Das Ergebnis Erläuterung Interviewfrage 3: Alle Mitarbeiter unter einem bestimmten Manager finden Lösung Abfrage Erläuterung der Lösungsabfrage Die Ergebnistabelle Die Erläuterung der Ergebnisse Für die Fragen 4 und 5 verwendete Tabellen Interviewfrage 4: Finden Sie die durchschnittliche Anzahl der Bestellungen Lösung Abfrage Lösung Abfrage Erläuterung Die Ergebnistabelle Die Erläuterung der Ergebnisse Interviewfrage 5: Finden Sie die Anzahl der aufeinanderfolgenden Tage mit Bestellung Lösung Abfrage Erläuterung zur Lösungsabfrage Die Ergebnistabelle Das Ergebnis Erläuterung Wann sind CTEs nützlich? Möchten Sie mehr über SQL Common Table Expressions wissen? 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! Tags: CTE SQL-Interviewfragen