教你如何使用MySQL8遞迴的方法
阿新 • • 發佈:2020-01-09
之前寫過一篇 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
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。