Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

MySQL 8 Expressões de Tabela Comuns CTE


MySQL 8 suporta expressões de tabela comuns, tanto não recursivas quanto recursivas, A CTE (Common Table Expression) é um conjunto de resultados temporário que você pode referenciar dentro de outra instrução SELECT, INSERT, UPDATE ou DELETE.

CTE não recursiva


Uma expressão de tabela comum (CTE) é como uma tabela derivada, mas sua declaração é colocada antes do bloco de consulta em vez de na cláusula FROM. Usando CTE, a subconsulta é avaliada apenas uma vez, as expressões de tabela comuns permitem o uso de conjuntos de resultados temporários nomeados, as expressões de tabela comuns são definidas na instrução usando o operador WITH.

Suponha que você queira descobrir a variação percentual nos pagamentos de cada ano em relação ao ano anterior. Sem CTE, você precisa escrever duas subconsultas e elas são essencialmente as mesmas. O MySQL não é inteligente o suficiente para detectar isso e as subconsultas são executadas duas vezes.
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 anos, SUM(valor) AS soma1 FROM pagamentos GROUP BY years) AS q1,(SELECT YEAR(paymentDate) AS years, SUM(amount) AS sum1 FROM payments GROUP BY years) AS q2WHEREq1.years =q2.years - 1;+-- -----+-----------+------------+------------+------ ------+| anos | próximo_ano | soma1 | next_sum | pct |+-------+-----------+------------+------------+- -----------+| 2003 | 2004 | 3250217.70 | 4313328.25 | 32.708903 || 2004 | 2005 | 4313328.25 | 1290293.28 | -70.085901 |+-------+-----------+------------+------------+ ------------+2 linhas no conjunto (0,01 seg)

Com CTE não recursiva, a consulta derivada é executada apenas uma vez e reutilizada
COM CTE_NAME AS (SELECT YEAR(paymentDate) AS anos, 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 DE CTE_NAME AS q1,CTE_NAME AS q2 WHERE q1.years =q2.years - 1;+-------+----------- ----+------------+------------+------------+| anos | próximo_ano | soma1 | next_sum | pct |+-------+-----------+------------+------------+- -----------+| 2003 | 2004 | 3250217.70 | 4313328.25 | 32.708903 || 2004 | 2005 | 4313328.25 | 1290293.28 | -70.085901 |+-------+-----------+------------+------------+ ------------+2 linhas no conjunto (0,00 seg)

Você pode notar que com o CTE, os resultados são os mesmos e o tempo de consulta melhora em 50%, a legibilidade é boa e pode ser referenciada várias vezes
CTEs podem se referir a outros CTEs:WITH cte1 AS (SELECT ... FROM ...), cte2 AS (SELECT ... FROM cte1 ...)SELECTFROM cte1, cte2 ...

CTEs recursivos


Um CTE recursivo é um CTE que faz referência a si mesmo. Ao fazer isso, o CTE inicial é executado repetidamente, retornando subconjuntos de dados, até que o resultado completo seja retornado
WITH RECURSIVE cte_name AS(cte_definition -- /* seed SELECT */UNION ALLcte_definition -- /* "recursive" SELECT */ referências cte_name.)-- Instrução usando CTESELECT *FROM cte_name

Seed SELECT é executado uma vez para criar o subconjunto de dados inicial; SELECT recursivo é executado repetidamente para retornar subconjuntos de dados até que o conjunto de resultados completo seja obtido. A recursão para quando uma iteração não gera novas linhas.

Suponha que você queira fazer a travessia de dados hierárquicos para produzir um organograma com a cadeia de gerenciamento de cada funcionário (ou seja, o caminho do CEO para um funcionário). Use um CTE recursivo! CTEs recursivos são adequados para consultar dados hierárquicos,

Criar a tabela
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));

inserir dados para obter a estrutura hierárquica
INSERT INTO mangeremp VALUES(333, "waqas", NULL), # waqas é o CEO (man_id is NULL)(198, "ali", 333), # ali tem ID 198 e reporta a 333 (waqas)( 692, "ahmed", 333), #ahmed reporte a waqas(29, "oasama", 198), #osama reporte a ali as alo has ref id 198(4610, "Mughees", 29), # Mughees reporte a osama (72, "aslam", 29),(123, "afrooz", 692);
COM 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;+------+----------- --+-----------------+| identificação | nome | caminho |+------+---------+-----------------+| 333 | waqas | 333 || 198 | todos | 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 linhas no conjunto (0,00 seg)
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 ---- consulta recursiva 
Cada linha produzida pela consulta recursiva encontra todos os funcionários que se reportam diretamente a um
funcionário produzido por uma linha anterior. Para cada funcionário, a linha inclui
ID do funcionário, nome e cadeia de gerenciamento de funcionários. A cadeia é a cadeia do gerente
com o ID do funcionário adicionado no final