MySQL 8 unterstützt allgemeine Tabellenausdrücke, sowohl nicht rekursiv als auch rekursiv. Ein CTE (Common Table Expression) ist eine temporäre Ergebnismenge, auf die Sie in einer anderen SELECT-, INSERT-, UPDATE- oder DELETE-Anweisung verweisen können.
Nicht rekursiver CTE
Ein allgemeiner Tabellenausdruck (CTE) ist genau wie eine abgeleitete Tabelle, aber seine Deklaration wird vor den Abfrageblock anstatt in die FROM-Klausel gestellt. Bei Verwendung von CTE wird die Unterabfrage nur einmal ausgewertet. Gemeinsame Tabellenausdrücke ermöglichen die Verwendung benannter temporärer Ergebnismengen. Gemeinsame Tabellenausdrücke werden innerhalb der Anweisung mithilfe des Operators WITH definiert.
Angenommen, Sie möchten die prozentuale Änderung der Zahlungen jedes Jahres im Vergleich zum Vorjahr ermitteln. Ohne CTE müssen Sie zwei Unterabfragen schreiben, die im Wesentlichen gleich sind. MySQL ist nicht intelligent genug, um das zu erkennen, und die Unterabfragen werden zweimal ausgeführt.
SELECT q1.years,q2.years AS next_year,q1.sum1,q2.sum1 AS next_sum,100 * (q2.sum1 - q1.sum1) / q1.sum1 AS pctFROM(SELECT YEAR(paymentDate) AS years, SUM(Betrag) AS Summe1 FROM Zahlungen GROUP BY Jahre) AS q1,(SELECT YEAR(Zahlungsdatum) AS Jahre, SUM(Betrag) AS Summe1 FROM Zahlungen GROUP BY Jahre) AS q2WHEREq1.years =q2.years - 1;+-- -----+-----------+----+------------+------ ------+| Jahre | nächstes_jahr | Summe1 | next_sum | pct |+-------+-----------+------------+------------+- -----------+| 2003 | 2004 | 3250217,70 | 4313328,25 | 32.708903 || 2004 | 2005 | 4313328,25 | 1290293.28 | -70,085901 |+-------+-----------+------------+------------+ -------------+2 Zeilen im Satz (0,01 Sek.)
Bei nicht-rekursivem CTE wird die abgeleitete Abfrage nur einmal ausgeführt und wiederverwendet
WITH CTE_NAME AS (SELECT YEAR(paymentDate) AS years, SUM(amount) AS sum1 FROM Payments GROUP BY years)SELECT q1.years,q2.years AS next_year,q1.sum1,q2.sum1 AS next_sum,100 * (q2.sum1 - q1.sum1) / q1.sum1 AS pct FROM CTE_NAME AS q1,CTE_NAME AS q2 WHERE q1.years =q2.years - 1;+-------+------- ----+------------+------------+------------+| Jahre | nächstes_jahr | Summe1 | next_sum | pct |+-------+-----------+------------+------------+- -----------+| 2003 | 2004 | 3250217,70 | 4313328,25 | 32.708903 || 2004 | 2005 | 4313328,25 | 1290293.28 | -70,085901 |+-------+-----------+------------+------------+ -------------+2 Zeilen im Satz (0,00 Sek.)
Sie werden vielleicht feststellen, dass mit CTE die Ergebnisse gleich sind und sich die Abfragezeit um 50 % verbessert, die Lesbarkeit gut ist und mehrfach referenziert werden kann
CTEs können auf andere CTEs verweisen:WITH cte1 AS (SELECT ... FROM ...), cte2 AS (SELECT ... FROM cte1 ...)SELECTFROM cte1, cte2 ...
Rekursive CTEs
Ein rekursiver CTE ist ein CTE, der auf sich selbst verweist. Dabei wird der anfängliche CTE wiederholt ausgeführt, wobei Teilmengen von Daten zurückgegeben werden, bis das vollständige Ergebnis zurückgegeben wird
WITH RECURSIVE cte_name AS(cte_definition -- /* Seed SELECT */UNION ALLcte_definition -- /* "rekursives" SELECT */ verweist auf cte_name.)-- Anweisung mit CTESELECT *FROM cte_name
Seed SELECT wird einmal ausgeführt, um die anfängliche Datenteilmenge zu erstellen; rekursives SELECT wird wiederholt ausgeführt, um Teilmengen von Daten zurückzugeben, bis die vollständige Ergebnismenge erhalten wird. Die Rekursion stoppt, wenn eine Iteration keine neuen Zeilen generiert.
Angenommen, Sie möchten eine hierarchische Datentraversierung durchführen, um ein Organigramm mit der Managementkette für jeden Mitarbeiter zu erstellen (d. h. den Weg vom CEO zum Mitarbeiter). Verwenden Sie einen rekursiven CTE! Rekursive CTEs eignen sich gut zum Abfragen hierarchischer Daten,
Tabelle erstellen
CREATE TABLE mangeremp (id INT PRIMARY KEY NOT NULL,name VARCHAR(100) NOT NULL,man_id INT NULL,INDEX (man_id),FOREIGN KEY (man_id) REFERENCES mangeremp (id));
Daten einfügen, um eine hierarchische Struktur zu erhalten
INSERT INTO mangeremp VALUES(333, "waqas", NULL), # waqas ist der CEO (man_id ist NULL)(198, "ali", 333), # ali hat ID 198 und untersteht 333 (waqas)( 692, "ahmed", 333), #ahmed berichten an waqas(29, "oasama", 198), #osama melden an ali, da alo die Ref-ID 198(4610, "Mughees", 29), # Mughees melden an osama (72, "aslam", 29),(123, "afrooz", 692);
WITH RECURSIVE emp_paths (id, name, path) AS (SELECT id, name, CAST(id AS CHAR(200)) FROM mangeremp WHERE mangeremp WHERE man_id IS NULL UNION ALL SELECT e.id, e.name, CONCAT(ep. path, ',', e.id) FROM emp_paths AS ep JOIN mangeremp AS e ON ep.id =e.man_id )SELECT * FROM emp_paths ORDER BY path;+------+------- --+----------------+| ID | Name | Pfad |+------+---------+-----------------+| 333 | Wakas | 333 || 198 | Ali | 333.198 || 29 | oasama | 333,198,29 || 4610 | Mughees | 333,198,29,4610 || 72 | Islam | 333,198,29,72 || 692 | Ahmed | 333.692 || 123 | afrooz | 333.692.123 |+------+---------+-----------------+7 Zeilen im Satz (0,00 Sek.)
SELECT e.id, e.name, CONCAT(ep.path, ',', e.id) FROM emp_paths AS ep JOIN mangeremp AS e ON ep.id =e.man_id ---- rekursive AbfrageJede von der rekursiven Abfrage erzeugte Zeile findet alle Mitarbeiter, die einem
Mitarbeiter direkt unterstellt sind, der von einer vorherigen Zeile erzeugt wurde. Für jeden dieser Mitarbeiter enthält die Zeile die
Mitarbeiter-ID, den Namen und die Mitarbeiterverwaltungskette. Die Kette ist die Kette des Managers
mit der am Ende hinzugefügten Mitarbeiter-ID