MySQL 8 prend en charge les expressions de table courantes, à la fois non récursives et récursives. Une CTE (Common Table Expression) est un ensemble de résultats temporaire que vous pouvez référencer dans une autre instruction SELECT, INSERT, UPDATE ou DELETE.
CTE non récursif
Une expression de table commune (CTE) est comme une table dérivée, mais sa déclaration est placée avant le bloc de requête au lieu de dans la clause FROM. À l'aide de CTE, la sous-requête n'est évaluée qu'une seule fois, les expressions de table communes permettent l'utilisation d'ensembles de résultats temporaires nommés, les expressions de table communes sont définies dans l'instruction à l'aide de l'opérateur WITH.
Supposons que vous souhaitiez connaître la variation en pourcentage des paiements de chaque année par rapport à l'année précédente. Sans CTE, vous devez écrire deux sous-requêtes, et elles sont essentiellement les mêmes. MySQL n'est pas assez intelligent pour le détecter et les sous-requêtes sont exécutées deux fois.
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(montant) AS sum1 FROM paiements GROUP BY ans) AS q1,(SELECT YEAR(paymentDate) AS ans, SUM(amount) AS sum1 FROM paiements GROUP BY ans) AS q2WHEREq1.years =q2.years - 1;+-- -----+-----------+------------+------------+------ ------+| ans | l'année_prochaine | somme1 | somme_suivante | pct |+-------+-----------+------------+------------+- -----------+| 2003 | 2004 | 3250217.70 | 4313328.25 | 32.708903 || 2004 | 2005 | 4313328.25 | 1290293.28 | -70.085901 |+-------+-----------+------------+------------+ ------------+2 lignes dans l'ensemble (0,01 sec)
Avec CTE non récursif, la requête dérivée est exécutée une seule fois et réutilisée
WITH CTE_NAME AS (SELECT YEAR(paymentDate) AS years, SUM(amount) AS sum1 FROM paiements 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;+-------+------- ----+------------+------------+------------+| ans | l'année_prochaine | somme1 | somme_suivante | pct |+-------+-----------+------------+------------+- -----------+| 2003 | 2004 | 3250217.70 | 4313328.25 | 32.708903 || 2004 | 2005 | 4313328.25 | 1290293.28 | -70.085901 |+-------+-----------+------------+------------+ ------------+2 lignes dans le jeu (0.00 sec)
Vous remarquerez peut-être qu'avec CTE, les résultats sont les mêmes et le temps de requête s'améliore de 50 %, la lisibilité est bonne et peut être référencé plusieurs fois
Les CTE peuvent faire référence à d'autres CTE :WITH cte1 AS (SELECT ... FROM ...), cte2 AS (SELECT ... FROM cte1 ...)SELECTFROM cte1, cte2 ...
CTE récursifs
Un CTE récursif est un CTE qui se référence lui-même. Ce faisant, le CTE initial est exécuté à plusieurs reprises, renvoyant des sous-ensembles de données, jusqu'à ce que le résultat complet soit renvoyé
WITH RECURSIVE cte_name AS(cte_definition -- /* seed SELECT */UNION ALLcte_definition -- /* "recursive" SELECT */ references cte_name.)-- Instruction utilisant CTESELECT *FROM cte_name
Seed SELECT est exécuté une fois pour créer le sous-ensemble de données initial ; SELECT récursif est exécuté à plusieurs reprises pour renvoyer des sous-ensembles de données jusqu'à ce que l'ensemble de résultats complet soit obtenu. La récursivité s'arrête lorsqu'une itération ne génère aucune nouvelle ligne.
Supposons que vous souhaitiez effectuer une traversée hiérarchique des données pour produire un organigramme avec la chaîne de gestion de chaque employé (c'est-à-dire le chemin du PDG à un employé). Utilisez un CTE récursif ! Les CTE récursifs sont bien adaptés à l'interrogation de données hiérarchiques,
Créer un tableau
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));
insérer des données afin d'obtenir une structure hiérarchisée
INSERT INTO mangeremp VALUES(333, "waqas", NULL), # waqas est le PDG (man_id est NULL)(198, "ali", 333), # ali a l'ID 198 et relève du 333 (waqas)( 692, "ahmed", 333), rapport de #ahmed à waqas(29, "oasama", 198), rapport de #osama à ali comme alo a ref id 198(4610, "Mughees", 29), rapport de # Mughees à 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 man_id IS NULL UNION ALL SELECT e.id, e.name, CONCAT(ep. chemin, ',', e.id) FROM emp_paths AS ep JOIN mangeremp AS e ON ep.id =e.man_id )SELECT * FROM emp_paths ORDER BY chemin;+------+------- --+-----------------+| identifiant | nom | chemin |+------+---------+-----------------+| 333 | waqas | 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 lignes dans l'ensemble (0,00 s)
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 ---- requête récursiveChaque ligne produite par la requête récursive trouve tous les employés qui relèvent directement d'un
employé produit par une ligne précédente. Pour chacun de ces employés, la ligne inclut
l'ID, le nom et la chaîne de gestion des employés. La chaîne est la chaîne du manager
avec l'identifiant de l'employé ajouté à la fin