![]()
測試環境為 CentOS 8 x86_64 , Mariadb 10.3.17-1 (虛擬機)
MariaDB 版本需要 10.2.2 以上才有支援 Recursive Common Table Expressions .
什麼是 CTE : Common Table Expressions ,它可以把 SELECT 後整個 Table 儲存起來,共後續 SQL 語法來使用.詳細說明請參考 – https://benjr.tw/102498
什麼是 Recursive Common Table Expressions (適用於存取階層式的資料)我們直接來看 MariaDB 提供的範例 – https://mariadb.com/kb/en/recursive-common-table-expressions-overview/ (以下圖示皆是來至於此)來說明.
[root@localhost ~]# mysql -u root -p Enter password: Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 2774 Server version: 10.3.27-MariaDB MariaDB Server Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MariaDB [(none)]> CREATE DATABASE testdb; Query OK, 1 row affected (0.001 sec) MariaDB [(none)]> USE testdb; Database changed MariaDB [testdb]> CREATE TABLE folks (id int(11) , name varchar(50), father varchar(50) , mother varchar(50)); Query OK, 0 rows affected (0.008 sec)
資料為親子的關係(誰是誰的父母親).
INSERT INTO folks VALUES
('100', 'Alex' , 20 , 30),
('20', 'Dad' , 10 , NULL),
('30', 'Mom', NULL , NULL),
('10', 'Grandpa Bill' , NULL , NULL),
('98', 'Sister Amy' , 20 , 30);
MariaDB [testdb]> INSERT INTO folks VALUES
-> ('100', 'Alex' , 20 , 30),
-> ('20', 'Dad' , 10 , NULL),
-> ('30', 'Mom', NULL , NULL),
-> ('10', 'Grandpa Bill' , NULL , NULL),
-> ('98', 'Sister Amy' , 20 , 30);
Query OK, 5 rows affected (0.002 sec)
Records: 5 Duplicates: 0 Warnings: 0
MariaDB [testdb]> SELECT * FROM folks;
+------+--------------+--------+--------+
| id | name | father | mother |
+------+--------------+--------+--------+
| 100 | Alex | 20 | 30 |
| 20 | Dad | 10 | NULL |
| 30 | Mom | NULL | NULL |
| 10 | Grandpa Bill | NULL | NULL |
| 98 | Sister Amy | 20 | 30 |
+------+--------------+--------+--------+
5 rows in set (0.001 sec)
我們要怎麼查詢 Alex 的親屬關係呢! 一般要透過好幾次的 SELECT 才能達成,透過 Recursive Common Table Expressions 可以快速達成.
WITH RECURSIVE ancestors AS ( SELECT * FROM folks WHERE name = 'Alex' UNION SELECT f.* FROM folks as f, ancestors AS a WHERE f.id = a.father or f.id = a.mother ) SELECT * FROM ancestors;
程式主要可以區分為兩區
- Anchor Part
只會執行一次,資料為外部資料表.SELECT * FROM folks WHERE name = 'Alex'
- Recursive Part
會重複執行直到 Where 判斷為非,資料為 CTE 本身資料表.SELECT f.* FROM folks as f, ancestors AS a WHERE f.id = a.father or f.id = a.mother
執行結果:
MariaDB [testdb]> WITH RECURSIVE ancestors AS (
-> SELECT * FROM folks
-> WHERE name = 'Alex'
-> UNION
-> SELECT f.*
-> FROM folks as f, ancestors AS a
-> WHERE
-> f.id = a.father or f.id = a.mother
-> )
-> SELECT * FROM ancestors;
+------+--------------+--------+--------+
| id | name | father | mother |
+------+--------------+--------+--------+
| 100 | Alex | 20 | 30 |
| 20 | Dad | 10 | NULL |
| 30 | Mom | NULL | NULL |
| 10 | Grandpa Bill | NULL | NULL |
+------+--------------+--------+--------+
4 rows in set (0.001 sec)
為什麼結果是這樣,我們來看一下官方的說明:
- 第一段 SELECT 會得到 Alex 本身的資料.
SELECT * FROM folks WHERE name = 'Alex'
- 第二段 SELECT 會得到 Alex 父母的資料.
SELECT f.* FROM folks as f, ancestors AS a WHERE f.id = a.father or f.id = a.mother
- FROM folks as f, ancestors AS a
依據兩個 Table 來做 FROM folks as f(原本的資料) ancestors AS a(剛剛 SELECT Alex 的資料) - WHERE f.id = a.father or f.id = a.mother
比對 f(原本的資料)的 id 與 a(剛剛 SELECT Alex 的資料) 的 father 或是 mother 相同 id 的.
- FROM folks as f, ancestors AS a
- RECURSIVE 會重覆第二段 SELECT 會拿 Alex 父母的資料去做比對.

這樣會查到 Alex 祖父母的資料.這時候 ancestors 資料表變成為 Alex 祖父母的資料.
- RECURSIVE 會重覆第二段 SELECT 會拿 Alex 祖父母的資料去做比對,沒有資料後就停止 RECURSIVE .
- 最後 UNION 這些資料.
- 最後透過 SELECT 讀取完整 ancestors 資料表的資料.
SELECT * FROM ancestors;
沒有解決問題,試試搜尋本站其他內容



