Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Wspólne wyrażenia tabelowe MySQL 8 CTE

MySQL 8 obsługuje popularne wyrażenia tabelowe, zarówno nierekurencyjne, jak i rekurencyjne, CTE (Common Table Expression) to tymczasowy zestaw wyników, do którego można się odwoływać w ramach innej instrukcji SELECT, INSERT, UPDATE lub DELETE.

Nierekurencyjne CTE

Wspólne wyrażenie tabelowe (CTE) jest podobne do tabeli pochodnej, ale jego deklaracja jest umieszczana przed blokiem zapytania, a nie w klauzuli FROM. Używając CTE, podzapytanie jest oceniane tylko raz, Wspólne wyrażenia tabelowe umożliwiają użycie nazwanych tymczasowych zestawów wyników, Wspólne wyrażenia tabelowe są definiowane w instrukcji za pomocą operatora WITH.

Załóżmy, że chcesz poznać procentową zmianę w płatnościach każdego roku w stosunku do roku poprzedniego. Bez CTE musisz napisać dwa podzapytania i są one zasadniczo takie same. MySQL nie jest wystarczająco inteligentny, aby to wykryć i podzapytania są wykonywane dwukrotnie.

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)

W przypadku nierekurencyjnego CTE wyprowadzone zapytanie jest wykonywane tylko raz i ponownie używane

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)

Możesz zauważyć, że przy CTE wyniki są takie same, a czas zapytania poprawia się o 50%, czytelność jest dobra i można się do niej wielokrotnie odwoływać

CTEs can refer to other CTEs:
WITH cte1 AS (SELECT ... FROM ...), cte2 AS (SELECT ... FROM cte1 ...)
SELECT
FROM cte1, cte2 ...

Rekursywne CTE

Rekurencyjne CTE to CTE, które odwołuje się do siebie. W ten sposób wielokrotnie wykonywane jest początkowe CTE, zwracając podzbiory danych, aż do zwrócenia pełnego wyniku

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 jest wykonywany raz w celu utworzenia początkowego podzbioru danych; rekursywny SELECT jest wielokrotnie wykonywany w celu zwrócenia podzbiorów danych, aż do uzyskania pełnego zestawu wyników. Rekurencja zatrzymuje się, gdy iteracja nie generuje żadnych nowych wierszy.

Załóżmy, że chcesz przeprowadzić hierarchiczne przechodzenie danych w celu utworzenia schematu organizacyjnego z łańcuchem zarządzania dla każdego pracownika (czyli ścieżki od dyrektora generalnego do pracownika). Użyj rekurencyjnego CTE! Rekurencyjne CTE są dobrze dostosowane do zapytań o dane hierarchiczne,

Utwórz tabelę

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)
);

wstawiaj dane, aby uzyskać hierarchiczną strukturę

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

Każdy wiersz utworzony przez zapytanie rekurencyjne znajduje wszystkich pracowników, którzy podlegają bezpośrednio
pracownikowi utworzonemu przez poprzedni wiersz. Dla każdego takiego pracownika wiersz zawiera
identyfikator pracownika, imię i nazwisko oraz łańcuch zarządzania pracownikami. Łańcuch to łańcuch menedżera
z dodanym na końcu identyfikatorem pracownika


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Policz z warunkiem IF w zapytaniu MySQL

  2. MySQL:Odmowa dostępu dla użytkownika 'test'@'localhost' (przy użyciu hasła:TAK) z wyjątkiem użytkownika root

  3. Grupowanie w interwał 5 minut w zakresie czasu

  4. Generowanie drzewa opartego na głębokości z danych hierarchicznych w MySQL (bez CTE)

  5. Jak naprawić:Nie znaleziono odpowiedniego sterownika dla błędu jdbc:mysql://localhost/dbname podczas korzystania z pul?