MySQL 8 admite expresiones de tabla comunes, tanto no recursivas como recursivas. Una CTE (expresión de tabla común) es un conjunto de resultados temporal al que puede hacer referencia dentro de otra instrucción SELECT, INSERT, UPDATE o DELETE.
CTE no recursivo
Una expresión de tabla común (CTE) es como una tabla derivada, pero su declaración se coloca antes del bloque de consulta en lugar de en la cláusula FROM. Con CTE, la subconsulta se evalúa solo una vez, las expresiones de tabla comunes permiten el uso de conjuntos de resultados temporales con nombre, las expresiones de tabla comunes se definen dentro de la instrucción mediante el operador CON.
Supongamos que desea conocer el cambio porcentual en los pagos de cada año con respecto al año anterior. Sin CTE, necesita escribir dos subconsultas, y son esencialmente iguales. MySQL no es lo suficientemente inteligente para detectar eso y las subconsultas se ejecutan dos veces.
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 (SELECT YEAR(paymentDate) AS years, SUM(amount) AS sum1 FROM payments GROUP BY years) AS q1, (SELECT YEAR(paymentDate) AS years, SUM(amount) AS sum1 FROM payments GROUP BY years) AS q2 WHERE q1.years = q2.years - 1; +-------+-----------+------------+------------+------------+ | years | next_year | sum1 | next_sum | pct | +-------+-----------+------------+------------+------------+ | 2003 | 2004 | 3250217.70 | 4313328.25 | 32.708903 | | 2004 | 2005 | 4313328.25 | 1290293.28 | -70.085901 | +-------+-----------+------------+------------+------------+ 2 rows in set (0.01 sec)
Con CTE no recursivo, la consulta derivada se ejecuta solo una vez y se reutiliza
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; +-------+-----------+------------+------------+------------+ | years | next_year | sum1 | next_sum | pct | +-------+-----------+------------+------------+------------+ | 2003 | 2004 | 3250217.70 | 4313328.25 | 32.708903 | | 2004 | 2005 | 4313328.25 | 1290293.28 | -70.085901 | +-------+-----------+------------+------------+------------+ 2 rows in set (0.00 sec)
Puede notar que con CTE, los resultados son los mismos y el tiempo de consulta mejora en un 50 %, la legibilidad es buena y se puede hacer referencia varias veces
CTEs can refer to other CTEs: WITH cte1 AS (SELECT ... FROM ...), cte2 AS (SELECT ... FROM cte1 ...) SELECT FROM cte1, cte2 ...
CTEs recursivos
Un CTE recursivo es un CTE que se referencia a sí mismo. Al hacerlo, el CTE inicial se ejecuta repetidamente, devolviendo subconjuntos de datos, hasta que se devuelve el resultado completo
WITH RECURSIVE cte_name AS ( cte_definition -- /* seed SELECT */ UNION ALL cte_definition -- /* "recursive" SELECT */ references cte_name. ) -- Statement using the CTE SELECT * FROM cte_name
Seed SELECT se ejecuta una vez para crear el subconjunto de datos inicial; SELECT recursivo se ejecuta repetidamente para devolver subconjuntos de datos hasta que se obtiene el conjunto de resultados completo. La recursividad se detiene cuando una iteración no genera filas nuevas.
Suponga que desea realizar un recorrido de datos jerárquicos para producir un organigrama con la cadena de gestión para cada empleado (es decir, la ruta desde el director ejecutivo hasta un empleado). ¡Use un CTE recursivo! Los CTE recursivos son muy adecuados para consultar datos jerárquicos,
Crear tabla
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) );
inserta datos para obtener una estructura jerárquica
INSERT INTO mangeremp VALUES (333, "waqas", NULL), # waqas is the CEO (man_id is NULL) (198, "ali", 333), # ali has ID 198 and reports to 333 (waqas) (692, "ahmed", 333), #ahmed report to waqas (29, "oasama", 198), #osama report to ali as alo has ref id 198 (4610, "Mughees", 29), # Mughees report to 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.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 | path | +------+---------+-----------------+ | 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 rows in set (0.00 sec)
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 ---- recursive query
Cada fila producida por la consulta recursiva encuentra todos los empleados que reportan directamente a un
empleado producido por una fila anterior. Para cada uno de esos empleados, la fila incluye la
identificación del empleado, el nombre y la cadena de gestión de empleados. La cadena es la cadena del gerente
con la identificación del empleado agregada al final