sql >> Base de Datos >  >> RDS >> Mysql

MySQL 8 Expresiones de tabla comunes CTE

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