MySQL 8 stöder vanliga tabelluttryck, både icke-rekursiva och rekursiva. En CTE (Common Table Expression) är en tillfällig resultatuppsättning som du kan referera till i en annan SELECT-, INSERT-, UPDATE- eller DELETE-sats.
Icke-rekursiv CTE
Ett vanligt tabelluttryck (CTE) är precis som en härledd tabell, men dess deklaration sätts före frågeblocket istället för i FROM-satsen. Med CTE utvärderas underfrågan endast en gång, vanliga tabelluttryck möjliggör användning av namngivna temporära resultatuppsättningar, gemensamma tabelluttryck definieras i satsen med operatorn WITH.
Anta att du vill ta reda på den procentuella förändringen av betalningarna för varje år jämfört med föregående år. Utan CTE måste du skriva två underfrågor, och de är i huvudsak desamma. MySQL är inte smart nog att upptäcka det och underfrågorna körs två gånger.
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(belopp) AS summa1 FROM betalningar GRUPPER EFTER år) AS q1,(SELECT YEAR(paymentDate) AS years, SUM(amount) AS summa1 FROM betalningar GROUP BY years) AS q2WHEREq1.years =q2.years - 1;+-- -----+-----------+------------+------------+------ ------+| år | nästa_år | summa1 | nästa_summa | pct |+-------+------------------------+- -----------+| 2003 | 2004 | 3250217,70 | 4313328.25 | 32.708903 || 2004 | 2005 | 4313328.25 | 1290293.28 | -70.085901 |+-------+-----------+------------+------------+ ------------+2 rader i set (0,01 sek)
Med icke-rekursiv CTE körs den härledda frågan endast en gång och återanvänds
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 FRÅN CTE_NAME AS q1,CTE_NAME AS q2 WHERE q1.years =q2.years - 1;+-------+------- ----+------------+------------+------------+| år | nästa_år | summa1 | nästa_summa | pct |+-------+------------------------+- -----------+| 2003 | 2004 | 3250217,70 | 4313328,25 | 32.708903 || 2004 | 2005 | 4313328,25 | 1290293.28 | -70.085901 |+-------+-----------+------------+------------+ ------------+2 rader i set (0,00 sek)
Du kanske märker att med CTE är resultaten desamma och frågetiden förbättras med 50 %, läsbarheten är bra och kan refereras flera gånger
CTE kan hänvisa till andra CTE:WITH cte1 AS (SELECT ... FROM ...), cte2 AS (SELECT ... FROM cte1 ...)SELECTFROM cte1, cte2 ...
Rekursiva CTE
En rekursiv CTE är en CTE som refererar till sig själv. Genom att göra så exekveras den initiala CTE upprepade gånger, vilket returnerar delmängder av data, tills det fullständiga resultatet returneras
MED RECURSIVE cte_name AS(cte_definition -- /* seed SELECT */UNION ALLcte_definition -- /* "rekursiv" SELECT */ refererar till cte_name.)-- Uttalande med CTESELECT *FROM cte_name
Seed SELECT exekveras en gång för att skapa den initiala datamängden; rekursiv SELECT exekveras upprepade gånger för att returnera delmängder av data tills den fullständiga resultatuppsättningen erhålls. Rekursionen upphör när en iteration inte genererar några nya rader.
Anta att du vill göra hierarkisk datatraversering för att producera ett organisationsschema med ledningskedjan för varje anställd (det vill säga vägen från VD till en anställd). Använd en rekursiv CTE! Rekursiva CTE:er är väl lämpade för att söka efter hierarkisk data,
Skapa tabell
SKAPA TABELL 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));
infoga data för att få hierarkisk struktur
INSERT INTO mangeremp VALUES(333, "waqas", NULL), # waqas är VD (man_id är NULL)(198, "ali", 333), # ali har ID 198 och rapporterar till 333 (waqas)( 692, "ahmed", 333), #ahmed rapporterar till waqas(29, "oasama", 198), #osama rapporterar till ali as alo har ref id 198(4610, "Mughees", 29), # Mughees rapporterar till osama (72, "aslam", 29),(123, "afrooz", 692);
MED RECURSIVE emp_paths (id, name, path) AS (SELECT id, name, CAST(id AS CHAR(200)) FRÅN mangeremp WHERE man_id IS NULL UNION ALL SELECT e.id, e.name, CONCAT(ep. sökväg, ',', 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 | namn | sökväg |+------+--------+-----------------+| 333 | waqas | 333 || 198 | ali | 333 198 || 29 | oasama | 333,198,29 || 4610 | Mughees | 333,198,29,4610 || 72 | aslam | 333,198,29,72 || 692 | ahmed | 333 692 || 123 | afrooz | 333 692 123 |+------+--------+----------------+7 rader i set (0,00 sek)
VÄLJ e.id, e.name, CONCAT(ep.path, ',', e.id) FROM emp_paths AS ep JOIN mangeremp AS e ON ep.id =e.man_id ---- rekursiv frågaVarje rad som produceras av den rekursiva frågan hittar alla anställda som rapporterar direkt till en
anställd som producerats av en tidigare rad. För varje sådan anställd innehåller raden
medarbetar-ID, namn och anställds ledningskedja. Kedjan är chefens kedja
med medarbetar-ID lagt till i slutet