MySQL Common Table Expressions (CTEs)

MySQLMySQLBeginner
Jetzt üben

💡 Dieser Artikel wurde von AI-Assistenten übersetzt. Um die englische Version anzuzeigen, können Sie hier klicken

Einführung

In diesem Lab lernen Sie, wie Sie Common Table Expressions (CTEs) in MySQL verwenden, um die Lesbarkeit und Wartbarkeit von Abfragen zu verbessern. Das Lab behandelt die Definition einfacher CTEs mit der WITH-Klausel, das Schreiben rekursiver CTEs für hierarchische Daten, das Verbinden von CTEs mit Tabellen und das Testen der Ausgabe von CTE-Abfragen.

Sie beginnen damit, eine Beispiel-Tabelle employees zu erstellen und dann einen einfachen CTE zu definieren, um Mitarbeiter aus der Abteilung 'Sales' auszuwählen. Dies wird die grundlegende Syntax und Verwendung von CTEs demonstrieren, indem komplexe Abfragen in kleinere, besser verwaltbare Teile aufgeteilt werden.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL mysql(("MySQL")) -.-> mysql/BasicKeywordsandStatementsGroup(["Basic Keywords and Statements"]) mysql/BasicKeywordsandStatementsGroup -.-> mysql/create_table("Table Creation") mysql/BasicKeywordsandStatementsGroup -.-> mysql/select("Data Retrieval") mysql/BasicKeywordsandStatementsGroup -.-> mysql/insert("Data Insertion") subgraph Lab Skills mysql/create_table -.-> lab-550903{{"MySQL Common Table Expressions (CTEs)"}} mysql/select -.-> lab-550903{{"MySQL Common Table Expressions (CTEs)"}} mysql/insert -.-> lab-550903{{"MySQL Common Table Expressions (CTEs)"}} end

Definition eines einfachen CTE mit der WITH-Klausel

In diesem Schritt lernen Sie, wie Sie einen einfachen Common Table Expression (CTE) mit der WITH-Klausel in MySQL definieren. CTEs sind temporäre, benannte Ergebnismengen, auf die Sie innerhalb einer einzelnen SELECT-, INSERT-, UPDATE- oder DELETE-Anweisung verweisen können. Sie sind nützlich, um komplexe Abfragen in kleinere, besser verwaltbare Teile aufzuteilen und so die Lesbarkeit und Wartbarkeit zu verbessern.

Grundlagen zu CTEs

Ein CTE ist im Wesentlichen eine benannte Unterabfrage, die nur während der Ausführung der Abfrage existiert. Es wird mit der WITH-Klausel definiert, gefolgt vom CTE-Namen, der Spaltenliste (optional) und dem Schlüsselwort AS, gefolgt von der in Klammern eingeschlossenen Unterabfrage.

Erstellen einer Beispiel-Tabelle

Zunächst erstellen wir eine einfache Tabelle namens employees, mit der wir arbeiten können. Führen Sie die folgenden SQL-Anweisungen in Ihrer MySQL-Umgebung aus. Sie können auf den MySQL-Befehlszeilenclient zugreifen, indem Sie einfach mysql in Ihrem Terminal eingeben.

mysql

Erstellen Sie dann die Tabelle:

CREATE TABLE employees (
    employee_id INT PRIMARY KEY,
    first_name VARCHAR(50),
    last_name VARCHAR(50),
    department VARCHAR(50),
    salary DECIMAL(10, 2)
);

INSERT INTO employees (employee_id, first_name, last_name, department, salary) VALUES
(1, 'John', 'Doe', 'Sales', 60000.00),
(2, 'Jane', 'Smith', 'Marketing', 75000.00),
(3, 'Robert', 'Jones', 'Sales', 55000.00),
(4, 'Emily', 'Brown', 'IT', 90000.00),
(5, 'Michael', 'Davis', 'Marketing', 70000.00);

Verlassen Sie nun den MySQL-Client:

exit

Definition eines einfachen CTE

Nun definieren wir einen einfachen CTE, um Mitarbeiter aus der Abteilung 'Sales' auszuwählen.

WITH SalesEmployees AS (
    SELECT employee_id, first_name, last_name, salary
    FROM employees
    WHERE department = 'Sales'
)
SELECT employee_id, first_name, last_name, salary
FROM SalesEmployees;

Erklärung:

  • WITH SalesEmployees AS (...): Dies definiert einen CTE namens SalesEmployees.
  • SELECT employee_id, first_name, last_name, salary FROM employees WHERE department = 'Sales': Dies ist die Unterabfrage, die die Mitarbeiterinformationen aus der employees-Tabelle auswählt, wenn die Abteilung 'Sales' ist.
  • SELECT employee_id, first_name, last_name, salary FROM SalesEmployees: Dies ist die Hauptabfrage, die alle Spalten aus dem SalesEmployees-CTE auswählt.

Ausführen der Abfrage

Um die Abfrage auszuführen, können Sie sie in einer Datei namens sales_employees.sql in Ihrem ~/project-Verzeichnis mit nano speichern:

nano ~/project/sales_employees.sql

Fügen Sie den SQL-Code in die Datei ein, speichern Sie ihn (Ctrl+O) und verlassen Sie die Datei (Ctrl+X).

Führen Sie dann die SQL-Datei mit dem MySQL-Befehlszeilenclient aus:

mysql < ~/project/sales_employees.sql

Erwartete Ausgabe:

Die Ausgabe sollte eine Tabelle sein, die die Mitarbeiter-ID, den Vornamen, den Nachnamen und das Gehalt aller Mitarbeiter aus der Abteilung 'Sales' enthält:

+-------------+------------+-----------+----------+
| employee_id | first_name | last_name | salary   |
+-------------+------------+-----------+----------+
|           1 | John       | Doe       | 60000.00 |
|           3 | Robert     | Jones     | 55000.00 |
+-------------+------------+-----------+----------+
2 rows in set (0.00 sec)

Dies zeigt, wie Sie einen einfachen CTE definieren und verwenden, um Daten aus einer Tabelle zu filtern. In den folgenden Schritten lernen Sie fortgeschrittene Techniken wie rekursive CTEs und das Verbinden von CTEs mit Tabellen kennen.

Schreiben eines rekursiven CTE für hierarchische Daten

In diesem Schritt lernen Sie, wie Sie einen rekursiven Common Table Expression (CTE) schreiben, um hierarchische Daten in MySQL abzufragen. Rekursive CTEs sind besonders nützlich für das Durchlaufen von baumartigen Strukturen wie Organigrammen, Dateisystemen oder Kategoriehierarchien.

Grundlagen zu rekursiven CTEs

Ein rekursiver CTE ist ein CTE, das sich selbst referenziert. Er besteht aus zwei Teilen:

  1. Anker-Mitglied: Dies ist der Basisfall, der den CTE initialisiert. Es handelt sich um eine normale SELECT-Anweisung, die den Startpunkt der Rekursion definiert.
  2. Rekursives Mitglied: Dieser Teil referenziert den CTE selbst und ermöglicht es dem CTE, durch die hierarchischen Daten zu iterieren. Es wird mit dem Anker-Mitglied mithilfe von UNION ALL kombiniert.

Erstellen einer Beispiel-Tabelle

Erstellen wir eine Tabelle namens employee_hierarchy, um die hierarchische Struktur von Mitarbeitern in einem Unternehmen darzustellen. Führen Sie die folgenden SQL-Anweisungen in Ihrer MySQL-Umgebung aus. Wenn Sie den MySQL-Client im vorherigen Schritt geschlossen haben, öffnen Sie ihn erneut, indem Sie mysql in Ihrem Terminal eingeben.

CREATE TABLE employee_hierarchy (
    employee_id INT PRIMARY KEY,
    employee_name VARCHAR(50),
    manager_id INT,
    FOREIGN KEY (manager_id) REFERENCES employee_hierarchy(employee_id)
);

INSERT INTO employee_hierarchy (employee_id, employee_name, manager_id) VALUES
(1, 'David', NULL),
(2, 'Emily', 1),
(3, 'Frank', 1),
(4, 'Grace', 2),
(5, 'Henry', 2),
(6, 'Ivy', 3),
(7, 'Jack', 3);

In dieser Tabelle:

  • employee_id ist der eindeutige Bezeichner für jeden Mitarbeiter.
  • employee_name ist der Name des Mitarbeiters.
  • manager_id ist die employee_id des Vorgesetzten des Mitarbeiters. Der oberste Manager hat für manager_id den Wert NULL.

Verlassen Sie nun den MySQL-Client:

exit

Schreiben eines rekursiven CTE

Nun schreiben wir einen rekursiven CTE, um die gesamte Hierarchie unter einem bestimmten Vorgesetzten abzurufen. In diesem Beispiel rufen wir die Hierarchie unter David (employee_id = 1) ab.

WITH RECURSIVE EmployeeHierarchyCTE AS (
    SELECT employee_id, employee_name, manager_id, 0 AS level
    FROM employee_hierarchy
    WHERE manager_id IS NULL  -- Anchor member: Select the top-level manager

    UNION ALL

    SELECT e.employee_id, e.employee_name, e.manager_id, h.level + 1
    FROM employee_hierarchy e
    INNER JOIN EmployeeHierarchyCTE h ON e.manager_id = h.employee_id  -- Recursive member: Join with the CTE itself
)
SELECT employee_id, employee_name, manager_id, level
FROM EmployeeHierarchyCTE
ORDER BY level, employee_name;

Erklärung:

  • WITH RECURSIVE EmployeeHierarchyCTE AS (...): Dies definiert einen rekursiven CTE namens EmployeeHierarchyCTE.
  • Anker-Mitglied:
    • SELECT employee_id, employee_name, manager_id, 0 AS level FROM employee_hierarchy WHERE manager_id IS NULL: Dies wählt den obersten Manager (David) aus und weist ihm die Ebene 0 zu.
  • Rekursives Mitglied:
    • SELECT e.employee_id, e.employee_name, e.manager_id, h.level + 1 FROM employee_hierarchy e INNER JOIN EmployeeHierarchyCTE h ON e.manager_id = h.employee_id: Dies verbindet die employee_hierarchy-Tabelle mit dem EmployeeHierarchyCTE über die manager_id, um alle Mitarbeiter zu finden, die jemandem im CTE unterstellt sind. Es erhöht die Ebene für jede Stufe der Hierarchie.
  • UNION ALL: Dies kombiniert die Ergebnisse des Anker- und des rekursiven Mitglieds.
  • SELECT employee_id, employee_name, manager_id, level FROM EmployeeHierarchyCTE ORDER BY level, employee_name: Dies ist die Hauptabfrage, die alle Spalten aus dem EmployeeHierarchyCTE auswählt und die Ergebnisse nach Ebene und Mitarbeiternamen sortiert.

Ausführen der Abfrage

Um die Abfrage auszuführen, können Sie sie in einer Datei namens employee_hierarchy.sql in Ihrem ~/project-Verzeichnis mit nano speichern:

nano ~/project/employee_hierarchy.sql

Fügen Sie den SQL-Code in die Datei ein, speichern Sie ihn (Ctrl+O) und verlassen Sie die Datei (Ctrl+X).

Führen Sie dann die SQL-Datei mit dem MySQL-Befehlszeilenclient aus:

mysql < ~/project/employee_hierarchy.sql

Erwartete Ausgabe:

Die Ausgabe sollte eine Tabelle sein, die die Mitarbeiterhierarchie unter David zeigt:

+-------------+---------------+------------+-------+
| employee_id | employee_name | manager_id | level |
+-------------+---------------+------------+-------+
|           1 | David         |       NULL |     0 |
|           2 | Emily         |          1 |     1 |
|           3 | Frank         |          1 |     1 |
|           4 | Grace         |          2 |     2 |
|           5 | Henry         |          2 |     2 |
|           6 | Ivy           |          3 |     2 |
|           7 | Jack          |          3 |     2 |
+-------------+---------------+------------+-------+
7 rows in set (0.00 sec)

Dies zeigt, wie Sie einen rekursiven CTE verwenden können, um hierarchische Daten abzufragen und die gesamte Hierarchie unter einem bestimmten Knoten abzurufen.

Verknüpfen eines CTE mit einer Tabelle

In diesem Schritt lernen Sie, wie Sie einen Common Table Expression (CTE) mit einer Tabelle in MySQL verknüpfen. Das Verknüpfen eines CTE mit einer Tabelle ermöglicht es Ihnen, die Ergebnisse des CTE mit Daten aus einer anderen Tabelle zu kombinieren und so komplexere Abfragen und Analysen durchzuführen.

Grundlagen zu CTE-Verknüpfungen

Das Verknüpfen eines CTE mit einer Tabelle ähnelt dem Verknüpfen von zwei Tabellen. Sie geben die Verknüpfungsbedingung mit dem Schlüsselwort JOIN und der ON-Klausel an. Der CTE wird innerhalb der Abfrage als virtuelle Tabelle behandelt.

Verwendung der bestehenden Tabellen

Wir werden weiterhin die in den vorherigen Schritten erstellten Tabellen employees und employee_hierarchy verwenden. Wenn Sie diese Schritte übersprungen haben, erstellen Sie die Tabellen bitte mit den in den Schritten 1 und 2 bereitgestellten SQL-Skripten.

Erstellen eines CTE für das durchschnittliche Gehalt nach Abteilung

Zunächst erstellen wir einen CTE, der das durchschnittliche Gehalt für jede Abteilung in der Tabelle employees berechnet.

WITH AvgSalaryByDepartment AS (
    SELECT department, AVG(salary) AS avg_salary
    FROM employees
    GROUP BY department
)
SELECT * FROM AvgSalaryByDepartment;

Dieser CTE, der AvgSalaryByDepartment heißt, berechnet das durchschnittliche Gehalt für jede Abteilung und gibt den Abteilungsnamen und das durchschnittliche Gehalt zurück.

Verknüpfen des CTE mit der Tabelle employees

Nun verknüpfen wir diesen CTE mit der Tabelle employees, um die Mitarbeiterinformationen zusammen mit dem durchschnittlichen Gehalt ihrer jeweiligen Abteilungen abzurufen.

WITH AvgSalaryByDepartment AS (
    SELECT department, AVG(salary) AS avg_salary
    FROM employees
    GROUP BY department
)
SELECT
    e.employee_id,
    e.first_name,
    e.last_name,
    e.department,
    e.salary,
    a.avg_salary
FROM
    employees e
JOIN
    AvgSalaryByDepartment a ON e.department = a.department;

Erklärung:

  • WITH AvgSalaryByDepartment AS (...): Dies definiert den CTE wie zuvor.
  • SELECT e.employee_id, e.first_name, e.last_name, e.department, e.salary, a.avg_salary FROM employees e JOIN AvgSalaryByDepartment a ON e.department = a.department: Dies wählt die Mitarbeiterinformationen aus der Tabelle employees und das durchschnittliche Gehalt aus dem CTE AvgSalaryByDepartment aus. Die JOIN-Klausel verbindet die beiden anhand der Spalte department.

Ausführen der Abfrage

Um die Abfrage auszuführen, können Sie sie in einer Datei namens employee_avg_salary.sql in Ihrem ~/project-Verzeichnis mit nano speichern:

nano ~/project/employee_avg_salary.sql

Fügen Sie den SQL-Code in die Datei ein, speichern Sie ihn (Ctrl+O) und verlassen Sie die Datei (Ctrl+X).

Führen Sie dann die SQL-Datei mit dem MySQL-Befehlszeilenclient aus:

mysql < ~/project/employee_avg_salary.sql

Erwartete Ausgabe:

Die Ausgabe sollte eine Tabelle sein, die die Mitarbeiterinformationen zusammen mit dem durchschnittlichen Gehalt ihrer Abteilung enthält:

+-------------+------------+-----------+-----------+----------+------------+
| employee_id | first_name | last_name | department | salary   | avg_salary |
+-------------+------------+-----------+-----------+----------+------------+
|           2 | Jane       | Smith     | Marketing | 75000.00 | 72500.00   |
|           5 | Michael    | Davis     | Marketing | 70000.00 | 72500.00   |
|           4 | Emily      | Brown     | IT        | 90000.00 | 90000.00   |
|           1 | John       | Doe       | Sales     | 60000.00 | 57500.00   |
|           3 | Robert     | Jones     | Sales     | 55000.00 | 57500.00   |
+-------------+------------+-----------+-----------+----------+------------+
5 rows in set (0.00 sec)

Dies zeigt, wie Sie einen CTE mit einer Tabelle verknüpfen können, um Daten zu kombinieren und komplexere Analysen durchzuführen.

Testen der Ausgabe von CTE-Abfragen

In diesem Schritt lernen Sie, wie Sie die Ausgabe Ihrer CTE-Abfragen testen, um sicherzustellen, dass sie die erwarteten Ergebnisse liefern. Dies ist ein entscheidender Schritt im Entwicklungsprozess, um die Richtigkeit Ihrer Abfragen zu überprüfen und eventuelle Probleme zu identifizieren. Wir werden die in den vorherigen Schritten erstellten Abfragen verwenden, um den Testprozess zu demonstrieren.

Warum sollten CTE-Abfragen getestet werden?

Das Testen von CTE-Abfragen ist aus mehreren Gründen wichtig:

  • Richtigkeit: Stellt sicher, dass die CTEs die richtigen Daten basierend auf der definierten Logik zurückgeben.
  • Datenintegrität: Überprüft, dass die Datenumwandlungen und Berechnungen innerhalb der CTEs korrekt sind.
  • Leistung: Hilft, potenzielle Leistungsprobleme in den CTE-Abfragen zu identifizieren.
  • Wartbarkeit: Erleichtert das Verständnis und die Wartung komplexer Abfragen, indem sie in kleinere, testbare Einheiten aufgeteilt werden.

Teststrategien

Es gibt mehrere Strategien zum Testen von CTE-Abfragen:

  1. Manuelle Inspektion: Untersuchen Sie die Ausgabe der CTE-Abfragen und vergleichen Sie sie mit den erwarteten Ergebnissen. Dies eignet sich für kleine Datensätze und einfache Abfragen.
  2. Automatisiertes Testen: Schreiben Sie Skripte oder Programme, um die CTE-Abfragen automatisch auszuführen und die Ausgabe mit vordefinierten Testfällen zu vergleichen. Dies ist effizienter für größere Datensätze und komplexere Abfragen.
  3. Unit-Testing: Testen Sie einzelne CTEs in Isolation, um sicherzustellen, dass sie korrekt funktionieren, bevor Sie sie in größere Abfragen integrieren.

Testen des einfachen CTE (Schritt 1)

Im Schritt 1 haben Sie einen einfachen CTE erstellt, um Mitarbeiter aus der Abteilung 'Sales' auszuwählen. Um diese Abfrage zu testen, können Sie die Ausgabe manuell untersuchen und überprüfen, dass sie nur Mitarbeiter aus der Abteilung 'Sales' enthält.

Führen Sie die folgende Abfrage erneut aus:

mysql < ~/project/sales_employees.sql

Die Ausgabe sollte wie folgt sein:

+-------------+------------+-----------+----------+
| employee_id | first_name | last_name | salary   |
+-------------+------------+-----------+----------+
|           1 | John       | Doe       | 60000.00 |
|           3 | Robert     | Jones     | 55000.00 |
+-------------+------------+-----------+----------+
2 rows in set (0.00 sec)

Überprüfen Sie, dass sowohl John Doe als auch Robert Jones tatsächlich in der Sales-Abteilung sind.

Testen des rekursiven CTE (Schritt 2)

Im Schritt 2 haben Sie einen rekursiven CTE erstellt, um die Mitarbeiterhierarchie abzurufen. Um diese Abfrage zu testen, können Sie die Ausgabe manuell untersuchen und überprüfen, dass sie die hierarchische Struktur korrekt darstellt.

Führen Sie die folgende Abfrage erneut aus:

mysql < ~/project/employee_hierarchy.sql

Die Ausgabe sollte wie folgt sein:

+-------------+---------------+------------+-------+
| employee_id | employee_name | manager_id | level |
+-------------+---------------+------------+-------+
|           1 | David         |       NULL |     0 |
|           2 | Emily         |          1 |     1 |
|           3 | Frank         |          1 |     1 |
|           4 | Grace         |          2 |     2 |
|           5 | Henry         |          2 |     2 |
|           6 | Ivy           |          3 |     2 |
|           7 | Jack          |          3 |     2 |
+-------------+---------------+------------+-------+
7 rows in set (0.00 sec)

Überprüfen Sie, dass David auf Ebene 0 ist, Emily und Frank David berichten (Ebene 1) und Grace, Henry, Ivy und Jack Emily oder Frank berichten (Ebene 2).

Testen der CTE-Verknüpfung (Schritt 3)

Im Schritt 3 haben Sie einen CTE mit der Tabelle employees verknüpft, um Mitarbeiterinformationen zusammen mit dem durchschnittlichen Gehalt ihrer Abteilung abzurufen. Um diese Abfrage zu testen, können Sie die Ausgabe manuell untersuchen und überprüfen, dass das durchschnittliche Gehalt für jede Abteilung korrekt berechnet wird.

Führen Sie die folgende Abfrage erneut aus:

mysql < ~/project/employee_avg_salary.sql

Die Ausgabe sollte wie folgt sein:

+-------------+------------+-----------+-----------+----------+------------+
| employee_id | first_name | last_name | department | salary   | avg_salary |
+-------------+------------+-----------+-----------+----------+------------+
|           2 | Jane       | Smith     | Marketing | 75000.00 | 72500.00   |
|           5 | Michael    | Davis     | Marketing | 70000.00 | 72500.00   |
|           4 | Emily      | Brown     | IT        | 90000.00 | 90000.00   |
|           1 | John       | Doe       | Sales     | 60000.00 | 57500.00   |
|           3 | Robert     | Jones     | Sales     | 55000.00 | 57500.00   |
+-------------+------------+-----------+-----------+----------+------------+
5 rows in set (0.00 sec)

Überprüfen Sie, dass das durchschnittliche Gehalt für die Marketing-Abteilung (75000 + 70000) / 2 = 72500 beträgt, das durchschnittliche Gehalt für die IT-Abteilung 90000 ist und das durchschnittliche Gehalt für die Sales-Abteilung (60000 + 55000) / 2 = 57500 beträgt.

Fazit

Durch das Testen der Ausgabe Ihrer CTE-Abfragen können Sie sicherstellen, dass sie korrekt funktionieren und die erwarteten Ergebnisse liefern. Dies trägt zur Verbesserung der Qualität und Zuverlässigkeit Ihrer Datenanalyse und -berichterstattung bei. Denken Sie daran, eine Kombination aus manueller Inspektion und automatisiertem Testen zu verwenden, um Ihre CTE-Abfragen gründlich zu validieren.

Zusammenfassung

In diesem Lab haben Sie gelernt, wie Sie Common Table Expressions (CTEs) in MySQL definieren und verwenden. Im ersten Schritt haben Sie eine Beispiel-Tabelle employees erstellt und dann einen einfachen CTE namens SalesEmployees mit der WITH-Klausel definiert. Dieser CTE hat Mitarbeiter aus der Abteilung 'Sales' ausgewählt und gezeigt, wie CTEs komplexe Abfragen in kleinere, besser handhabbare Teile aufteilen können, was die Lesbarkeit verbessert.

Das Lab hat das Konzept von CTEs als temporäre, benannte Ergebnismengen eingeführt, die nur während der Ausführung der Abfrage existieren. Sie haben gelernt, dass CTEs mit der WITH-Klausel definiert werden, gefolgt vom CTE-Namen und der in Klammern eingeschlossenen Unterabfrage. Das Beispiel hat gezeigt, wie man Daten aus dem CTE in einer nachfolgenden SELECT-Anweisung auswählt.