MySQL中普通CTE和遞歸CTE的順序問題小結(jié)
本文主要探討mysql中with普通cte與遞歸cte如何混合使用。
一、with用法系列文章
關(guān)于with用法與with RECURSIVE的用法可以參考本人的另外兩篇博文。
二、前言
在使用with RECURSIVE 遞歸查詢的過程中,發(fā)現(xiàn)有一段sql是公共的,因此想把這部分sql提取出去,當(dāng)做臨時(shí)表。 with as子查詢就可以當(dāng)做臨時(shí)表,所以我就在想能不能先用with as把公共部分查詢成臨時(shí)表,后面再跟著with RECURSIVE 遞歸查詢。即with as與with RECURSIVE 混合使用。
經(jīng)測試后發(fā)現(xiàn)先普通CTE再遞歸CTE時(shí)sql報(bào)錯(cuò) ,所以我想知道是否能混合使用,本文就是來討論這個(gè)問題。
原生sql示例如下:
-- 查詢?nèi)蝿?wù)2子節(jié)點(diǎn)
WITH RECURSIVE cte AS (
SELECT r.id,r.project_code, r.code, r.name,r.parent_project_code,r.parent_code
FROM t_ds_process_dependent_relation r
inner join t_ds_process_definition d on r.project_code = d.project_code and r.code = d.code and r.version = d.version
WHERE r.code = 18418446171042 -- 任務(wù)2
UNION ALL
SELECT t.id,t.project_code, t.code, t.name,t.parent_project_code,t.parent_code
FROM t_ds_process_dependent_relation t
inner join t_ds_process_definition d on t.project_code = d.project_code and t.code = d.code and t.version = d.version
INNER JOIN cte c ON t.parent_project_code = c.project_code and t.parent_code = c.code
)
SELECT * FROM cte;
如下圖:sql中有部分是公共的

在我的設(shè)想里,我想把公共部分提取成普通CTE, 然后在遞歸CTE中引用,但是這種語法在mysql中是錯(cuò)誤的
錯(cuò)誤SQL如下:
with relation as ( -- 普通CTE
SELECT r.id,r.project_code, r.code, r.name,r.parent_project_code,r.parent_code
FROM t_ds_process_dependent_relation r
inner join t_ds_process_definition d on r.project_code = d.project_code and r.code = d.code and r.version = d.version
),
RECURSIVE cte AS ( -- 遞歸CTE
SELECT id,project_code, code, name,parent_project_code,parent_code
FROM relation
WHERE code = 18418446171042 -- 任務(wù)2
UNION ALL
SELECT t.id,t.project_code, t.code, t.name,t.parent_project_code,t.parent_code
FROM relation t
INNER JOIN cte c ON t.parent_project_code = c.project_code and t.parent_code = c.code
)
SELECT * FROM cte;
三、MySQL 普通CTE與遞歸CTE混合使用的嚴(yán)格規(guī)則
在 MySQL 中,不可以 先定義普通 CTE 再定義遞歸 CTE。這是 MySQL 與某些其他數(shù)據(jù)庫(如 PostgreSQL)的一個(gè)重要語法差異。
MySQL 的嚴(yán)格規(guī)則
- 必須將
RECURSIVE關(guān)鍵字緊跟在WITH之后 - 第一個(gè) CTE 必須是遞歸 CTE(如果使用了 RECURSIVE 關(guān)鍵字)
- 所有 CTE(包括普通 CTE)都必須放在同一個(gè) WITH RECURSIVE 塊中
正確寫法示例:
WITH RECURSIVE
-- 必須先定義遞歸CTE
recursive_cte AS (
-- 基礎(chǔ)部分
SELECT ...
UNION ALL
-- 遞歸部分
SELECT ... FROM recursive_cte ...
),
-- 然后才能定義普通CTE
normal_cte AS (
SELECT ... FROM ...
)
-- 主查詢
SELECT ... FROM recursive_cte JOIN normal_cte ...
錯(cuò)誤寫法示例:
-- 這樣寫會(huì)報(bào)錯(cuò)!
WITH
normal_cte AS (SELECT ...), -- 先普通CTE
RECURSIVE -- 后RECURSIVE
recursive_cte AS (SELECT ...)
SELECT ...
四、解決方案
如果確實(shí)需要先處理普通 CTE 再處理遞歸 CTE,可以考慮以下方法:
4.1、方法1:相互依賴的遞歸CTE
下述示例中定義了兩個(gè)遞歸CET, 兩個(gè)CTE之間可以相互引用
WITH RECURSIVE
cte1 AS (
SELECT id, parent_id, name, 1 AS level
FROM tree WHERE parent_id IS NULL
UNION ALL
SELECT t.id, t.parent_id, t.name, cte1.level + 1
FROM tree t JOIN cte1 ON t.parent_id = cte1.id
),
cte2 AS (
-- 這個(gè)CTE依賴于cte1的結(jié)果
SELECT id, COUNT(*) AS child_count
FROM cte1 GROUP BY id
)
SELECT cte1.*, cte2.child_count
FROM cte1 LEFT JOIN cte2 ON cte1.id = cte2.id;
按照本文中的示例,我們想先寫with as語句把臨時(shí)表先提取出來,然后再with recursive開始遞歸,但是這種寫法是錯(cuò)誤的。因此按照方法一的解決方法:把with as提取出的臨時(shí)表變成with recursive的寫法,但是只包含基礎(chǔ)查詢部分,不包含遞歸,然后在下面的遞歸部分中引用臨時(shí)表。
即SQL如下:
with RECURSIVE
relation as ( -- 遞歸CTE但是只有基礎(chǔ)查詢部分,沒有union all遞歸部分
SELECT r.id,r.project_code, r.code, r.name,r.parent_project_code,r.parent_code
FROM t_ds_process_dependent_relation r
inner join t_ds_process_definition d on r.project_code = d.project_code and r.code = d.code and r.version = d.version
),
cte AS ( -- 遞歸CTE
SELECT id,project_code, code, name,parent_project_code,parent_code
FROM relation
WHERE code = 18418446171042 -- 任務(wù)2
UNION ALL
SELECT t.id,t.project_code, t.code, t.name,t.parent_project_code,t.parent_code
FROM relation t
INNER JOIN cte c ON t.parent_project_code = c.project_code and t.parent_code = c.code
)
select * from cte;
上述這種語法在Mysql8.0+版本中是支持的。
4.2、方法2:嵌套查詢
WITH RECURSIVE
-- 將普通CTE的邏輯嵌入到遞歸CTE的基礎(chǔ)部分
recursive_cte AS (
-- 基礎(chǔ)部分包含普通CTE邏輯
WITH normal_cte AS (SELECT ...)
SELECT ... FROM normal_cte WHERE ...
UNION ALL
-- 遞歸部分
SELECT ... FROM recursive_cte ...
)
SELECT ... FROM recursive_cte;
4.3、方法3:使用臨時(shí)表
-- 先創(chuàng)建臨時(shí)表存儲(chǔ)普通CTE結(jié)果
CREATE TEMPORARY TABLE temp_normal AS
SELECT ... FROM ...;
-- 然后使用遞歸CTE
WITH RECURSIVE recursive_cte AS (
SELECT ... FROM temp_normal ...
)
SELECT ... FROM recursive_cte;
-- 最后刪除臨時(shí)表
DROP TEMPORARY TABLE temp_normal;
4.4、方法4:分開執(zhí)行(應(yīng)用層處理)
-- 第一個(gè)查詢:執(zhí)行普通CTE
SET @var = (SELECT ... FROM ...);
-- 第二個(gè)查詢:執(zhí)行遞歸CTE
WITH RECURSIVE recursive_cte AS (
SELECT ... WHERE ... = @var
)
SELECT ... FROM recursive_cte;
到此這篇關(guān)于MySQL中普通CTE和遞歸CTE的順序問題小結(jié)的文章就介紹到這了,更多相關(guān)MySQL普通CTE和遞歸CTE內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- MySQL CTE (Common Table Expressions)示例全解析
- MySQL CTE 通用表達(dá)式詳解
- 如何使用 Spring Boot 3.3 和 JdbcTemplate 操作 MySQL 數(shù)據(jù)庫
- MySQL中使用CTE獲取時(shí)間段數(shù)據(jù)的技巧分享
- MySQL數(shù)據(jù)庫中遇到no?database?selected問題解決辦法
- Mysql8公用表表達(dá)式CTE詳解
- MySQL8.0之CTE(公用表表達(dá)式)的使用
- 解決mysql報(bào)錯(cuò):Data?source?rejected?establishment?of?connection,?message?from?server:?\"Too?many?connectio
- MySQL數(shù)據(jù)庫之字符集?character
- mysql8 公用表表達(dá)式CTE的使用方法實(shí)例分析
相關(guān)文章
定時(shí)備份mysql, 定時(shí)切割nginx access log的方法
定時(shí)備份mysql, 定時(shí)切割nginx access log的方法,需要的朋友可以參考下。2011-09-09
mysql獲取字符串長度函數(shù)(CHAR_LENGTH)
本文介紹一下關(guān)于mysql獲取字符串長度的方法,希望此教程對各位同學(xué)會(huì)有所幫助哦。2013-11-11
Mysql主從復(fù)制(master-slave)實(shí)際操作案例
這篇文章主要介紹了Mysql主從復(fù)制(master-slave)實(shí)際操作案例,同時(shí)介紹了Mysql grant 用戶授權(quán)的相關(guān)內(nèi)容,需要的朋友可以參考下2014-06-06
win10下MySQL 8.0登錄Access denied for user‘root’@‘localhost’ (u
這篇文章主要介紹了win10下MySQL 8.0登錄Access denied for user‘root’@‘localhost’ (using password: YES)問題的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-03-03
MySQL啟動(dòng)失敗報(bào)錯(cuò):mysqld.service failed to run 
在日常運(yùn)維中,MySQL 作為廣泛應(yīng)用的關(guān)系型數(shù)據(jù)庫,其穩(wěn)定性和可用性至關(guān)重要,然而,有時(shí)系統(tǒng)升級(jí)或配置變更后,MySQL 服務(wù)可能會(huì)出現(xiàn)無法啟動(dòng)的問題,本文針對某次實(shí)際案例進(jìn)行深入分析和處理,需要的朋友可以參考下2024-12-12
SPSS連接mysql數(shù)據(jù)庫的超詳細(xì)操作教程
小編最近在學(xué)習(xí)SPSS,在為數(shù)據(jù)庫建立連接時(shí)真的踩了很多坑,這篇文章主要給大家介紹了關(guān)于SPSS連接mysql數(shù)據(jù)庫的超詳細(xì)操作教程,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-02-02
MySQL 參數(shù)相關(guān)概念及查詢更改方法
這篇文章主要介紹了MySQL 參數(shù)相關(guān)概念及查詢更改方法,幫助大家更好的理解和使用MySQL數(shù)據(jù)庫,感興趣的朋友可以了解下2020-09-09

