1. 程式人生 > 資料庫 >教你如何使用MySQL8遞迴的方法

教你如何使用MySQL8遞迴的方法

之前寫過一篇 MySQL通過自定義函式的方式,遞迴查詢樹結構,從MySQL 8.0 開始終於支援了遞迴查詢的語法

CTE

首先了解一下什麼是 CTE,全名 Common Table Expressions

WITH
 cte1 AS (SELECT a,b FROM table1),cte2 AS (SELECT c,d FROM table2)
SELECT b,d FROM cte1 JOIN cte2
WHERE cte1.a = cte2.c;

cte1,cte2 為我們定義的CTE,可以在當前查詢中引用

可以看出 CTE 就是一個臨時結果集,和派生表類似,二者的區別這裡不細說,可以參考下MySQL開發文件:https://dev.mysql.com/doc/refman/8.0/en/with.html#common-table-expressions-recursive-examples

遞迴查詢

先來看下遞迴查詢的語法

WITH RECURSIVE cte_name AS
(
  SELECT ...   -- return initial row set
  UNION ALL / UNION DISTINCT
  SELECT ...   -- return additional row sets
)
SELECT * FROM cte;
  • 定義一個CTE,這個CTE 最終的結果集就是我們想要的 ”遞迴得到的樹結構",RECURSIVE 代表當前 CTE 是遞迴的
  • 第一個SELECT 為 “初始結果集”
  • 第二個SELECT 為遞迴部分,利用 "初始結果集/上一次遞迴返回的結果集" 進行查詢得到 “新的結果集”
  • 直到遞迴部分結果集返回為null,查詢結束
  • 最終UNION ALL 會將上述步驟中的所有結果集合並(UNION DISTINCT 會進行去重),再通過 SELECT * FROM cte; 拿到所有的結果集

遞迴部分不能包括:

  • 聚合函式例如 SUM()
  • GROUP BY
  • ORDER BY
  • LIMIT
  • DISTINCT

上面的講解可能有點抽象,通過例子慢慢來理解

WITH RECURSIVE cte (n) AS -- 這裡定義的n相當於結果集的列名,也可在下面查詢中定義
(
 SELECT 1
 UNION ALL
 SELECT n + 1 FROM cte WHERE n < 5
)
SELECT * FROM cte;


-- result
+------+
| n  |
+------+
|  1 |
|  2 |
|  3 |
|  4 |
|  5 |
+------+

  • 初始結果集為 n =1
  • 這時候看遞迴部分,第一次執行 CTE結果集即是 n =1,條件發現並不滿足 n < 5,返回 n + 1
  • 第二次執行遞迴部分,CTE結果集為 n = 2,遞迴... 直至條件不滿足
  • 最後合併結果集

EXAMPLE

最後來看一個樹結構的例子

CREATE TABLE `c_tree` (
 `id` int(11) NOT NULL AUTO_INCREMENT,`cname` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,`parent_id` int(11) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
mysql> select * from c_tree;
+----+---------+-----------+
| id | cname  | parent_id |
+----+---------+-----------+
| 1 | 1    |     0 |
| 2 | 2    |     0 |
| 3 | 3    |     0 |
| 4 | 1-1   |     1 |
| 5 | 1-2   |     1 |
| 6 | 2-1   |     2 |
| 7 | 2-2   |     2 |
| 8 | 3-1   |     3 |
| 9 | 3-1-1  |     8 |
| 10 | 3-1-2  |     8 |
| 11 | 3-1-1-1 |     9 |
| 12 | 3-2   |     3 |
+----+---------+-----------+
mysql> 
WITH RECURSIVE tree_cte as
(
  select * from c_tree where parent_id = 3
  UNION ALL
  select t.* from c_tree t inner join tree_cte tcte on t.parent_id = tcte.id
)
SELECT * FROM tree_cte;
+----+---------+-----------+
| id | cname  | parent_id |
+----+---------+-----------+
| 8 | 3-1   |     3 |
| 12 | 3-2   |     3 |
| 9 | 3-1-1  |     8 |
| 10 | 3-1-2  |     8 |
| 11 | 3-1-1-1 |     9 |
+----+---------+-----------+
  • 初始結果集R0 = select * from c_tree where parent_id = 3
  • 遞迴部分,第一次 R0 與 c_tree inner join 得到 R1
  • R1 再與 c_tree inner join 得到 R2
  • ...
  • 合併所有結果集 R0 + ... + Ri

更多資訊

https://dev.mysql.com/doc/refman/8.0/en/with.html

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。