MySQL 8 поддържа общи изрази за таблици, както нерекурсивни, така и рекурсивни, A CTE (Общ израз на таблица) е временен набор от резултати, който можете да препратите в друг израз SELECT, INSERT, UPDATE или DELETE.
Нерекурсивна CTE
Обикновеният табличен израз (CTE) е точно като производна таблица, но неговата декларация се поставя преди блока на заявката вместо в клаузата FROM. С помощта на CTE подзаявката се оценява само веднъж, изразите на общата таблица позволяват използването на наименувани временни резултативни набори, общите изрази за таблица се дефинират в рамките на оператора с помощта на оператора WITH.
Да предположим, че искате да разберете процентната промяна в плащанията за всяка година спрямо предходната година. Без CTE трябва да напишете две подзаявки и те по същество са еднакви. MySQL не е достатъчно интелигентен, за да открие това и подзаявките се изпълняват два пъти.
SELECT q1.years,q2.years AS next_year,q1.sum1,q2.sum1 AS next_sum,100 * (q2.sum1 - q1.sum1) / q1.sum1 КАТО pctFROM(SELECT YEAR(paymentDate) AS години, SUM(сума) КАТО сума1 ОТ плащания ГРУПА ПО години) КАТО q1,(ИЗБЕРЕТЕ ГОДИНА(дата на плащане) КАТО години, SUM(сума) КАТО сума1 ОТ плащания ГРУПА ПО години) КАТО q2WHEREq1.години =q2.години - 1;+-- -----+----------+------------+------------+------ ------+| години | следващата_година | сума1 | следваща_сума | pct |+-------+-----------+-----------+------------+- -----------+| 2003 г. | 2004 | 3250217,70 | 4313328.25 | 32,708903 || 2004 | 2005 г. | 4313328.25 | 1290293.28 | -70,085901 |+-------+-----------+------------+------------+ ------------+2 реда в комплект (0,01 сек)
При нерекурсивна CTE извлечената заявка се изпълнява само веднъж и се използва повторно
С CTE_NAME КАТО (ИЗБЕРЕТЕ ГОДИНА(дата на плащане) КАТО години, SUM(сума) КАТО sum1 ОТ плащания ГРУПА ПО години)ИЗБЕРЕТЕ q1.years,q2.years КАТО следващата_година,q1.sum1,q2.sum1 КАТО следваща_сума,100 * (q2.sum1 - q1.sum1) / q1.sum1 AS pct FROM CTE_NAME AS q1,CTE_NAME AS q2 КЪДЕ q1.години =q2.години - 1;+-------+------- ----+-----------+------------+------------+| години | следващата_година | сума1 | следваща_сума | pct |+-------+-----------+-----------+------------+- -----------+| 2003 г. | 2004 | 3250217,70 | 4313328.25 | 32,708903 || 2004 | 2005 г. | 4313328.25 | 1290293.28 | -70,085901 |+-------+-----------+------------+------------+ ------------+2 реда в комплект (0,00 сек.)
Може да забележите, че с CTE резултатите са едни и същи и времето за заявка се подобрява с 50%, четливостта е добра и може да се препраща многократно
CTE могат да се отнасят до други CTE:WITH cte1 AS (SELECT ... FROM ...), cte2 AS (SELECT ... FROM cte1 ...)SELECTFROM cte1, cte2 ...
Рекурсивни CTEs
Рекурсивният CTE е CTE, който се позовава на себе си. При това първоначалният CTE се изпълнява многократно, връщайки подмножества от данни, докато се върне пълният резултат
С РЕКУРСИВНО cte_name AS(cte_definition -- /* seed SELECT */UNION ALLcte_definition -- /* "рекурсивен" SELECT */ препраща cte_name.)-- Инструкция, използваща CTESELECT *FROM cte_name
Seed SELECT се изпълнява веднъж, за да се създаде първоначалното подмножество от данни; рекурсивният SELECT се изпълнява многократно за връщане на подмножества от данни, докато се получи пълен набор от резултати. Рекурсията спира, когато една итерация не генерира нови редове.
Да предположим, че искате да извършите йерархично обхождане на данни, за да създадете организационна диаграма с веригата на управление за всеки служител (тоест пътя от главния изпълнителен директор до служител). Използвайте рекурсивен CTE! Рекурсивните CTE са много подходящи за запитване на йерархични данни,
Създайте таблица
СЪЗДАВАНЕ НА ТАБЛИЦА mangeremp (id INT ПРАВИЛЕН КЛЮЧ НЕ NULL, име VARCHAR(100) НЕ НУЛ, man_id INT NULL, INDEX (man_id), ВЪНШЕН КЛЮЧ (man_id) РЕФЕРЕНЦИИ mangeremp (id));
вмъкнете данни, за да получите йерархична структура
INSERT INTO mangeremp VALUES(333, "waqas", NULL), # waqas е главен изпълнителен директор (man_id е NULL)(198, "ali", 333), # ali има ID 198 и докладва на 333 (waqas)( 692, "ahmed", 333), #ahmed докладва на waqas(29, "oasama", 198), #osama докладва на ali as alo има ref id 198(4610, "Mughees", 29), # Mughees докладва на osama (72, "aslam", 29), (123, "afrooz", 692);
С РЕКУРСИВНИ emp_paths (id, име, път) AS (SELECT id, name, CAST(id AS CHAR(200)) FROM mangeremp WHERE man_id Е NULL UNION ALL SELECT e.id, e.name, CONCAT(ep. път, ',', e.id) ОТ emp_paths КАТО ep JOIN mangeremp AS e ON ep.id =e.man_id )SELECT * FROM emp_paths ORDER BY path;+-------+------- --+----------------+| ID | име | път |+------+---------+----------------+| 333 | waqas | 333 || 198 | али | 333 198 || 29 | оасама | 333,198,29 || 4610 | Mughees | 333,198,29,4610 || 72 | аслам | 333,198,29,72 || 692 | ахмед | 333 692 || 123 | afrooz | 333 692 123 |+------+--------+----------------+7 реда в комплект (0,00 сек)
ИЗБЕРЕТЕ e.id, e.name, CONCAT(ep.path, ',', e.id) FROM emp_paths AS ep JOIN mangeremp AS e ON ep.id =e.man_id ---- рекурсивна заявкапредварително>Всеки ред, произведен от рекурсивната заявка, намира всички служители, които се отчитат директно на
служител, създаден от предишен ред. За всеки такъв служител редът включва
идентификационния номер на служителя, името и веригата за управление на служителите. Веригата е веригата на мениджъра
с добавен идентификационен номер на служител в края