MySQL中普通CTE和遞歸CTE的順序問(wèn)題小結(jié)
本文主要探討mysql
中with普通cte
與遞歸cte
如何混合使用。
一、with用法系列文章
關(guān)于with用法與with RECURSIVE的用法可以參考本人的另外兩篇博文。
二、前言
在使用with RECURSIVE
遞歸查詢的過(guò)程中,發(fā)現(xiàn)有一段sql是公共的,因此想把這部分sql提取出去,當(dāng)做臨時(shí)表。 with as
子查詢就可以當(dāng)做臨時(shí)表,所以我就在想能不能先用with as
把公共部分查詢成臨時(shí)表,后面再跟著with RECURSIVE
遞歸查詢。即with as
與with RECURSIVE
混合使用。
經(jīng)測(cè)試后發(fā)現(xiàn)先普通CTE再遞歸CTE時(shí)sql報(bào)錯(cuò) ,所以我想知道是否能混合使用,本文就是來(lái)討論這個(gè)問(wèn)題。
原生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中引用,但是這種語(yǔ)法在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ù)庫(kù)(如 PostgreSQL)的一個(gè)重要語(yǔ)法差異。
MySQL 的嚴(yán)格規(guī)則
- 必須將
RECURSIVE
關(guān)鍵字緊跟在WITH
之后 - 第一個(gè) CTE 必須是遞歸 CTE(如果使用了 RECURSIVE 關(guān)鍵字)
- 所有 CTE(包括普通 CTE)都必須放在同一個(gè) WITH RECURSIVE 塊中
正確寫(xiě)法示例:
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ò)誤寫(xiě)法示例:
-- 這樣寫(xiě)會(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;
按照本文中的示例,我們想先寫(xiě)with as語(yǔ)句把臨時(shí)表先提取出來(lái),然后再with recursive開(kāi)始遞歸,但是這種寫(xiě)法是錯(cuò)誤的。因此按照方法一的解決方法:把with as提取出的臨時(shí)表變成with recursive的寫(xiě)法,但是只包含基礎(chǔ)查詢部分,不包含遞歸,然后在下面的遞歸部分中引用臨時(shí)表。
即SQL如下:
with RECURSIVE relation as ( -- 遞歸CTE但是只有基礎(chǔ)查詢部分,沒(méi)有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;
上述這種語(yǔ)法在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:分開(kāi)執(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的順序問(wèn)題小結(jié)的文章就介紹到這了,更多相關(guān)MySQL普通CTE和遞歸CTE內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- MySQL CTE (Common Table Expressions)示例全解析
- MySQL CTE 通用表達(dá)式詳解
- 如何使用 Spring Boot 3.3 和 JdbcTemplate 操作 MySQL 數(shù)據(jù)庫(kù)
- MySQL中使用CTE獲取時(shí)間段數(shù)據(jù)的技巧分享
- MySQL數(shù)據(jù)庫(kù)中遇到no?database?selected問(wèn)題解決辦法
- 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ù)庫(kù)之字符集?character
- mysql8 公用表表達(dá)式CTE的使用方法實(shí)例分析
相關(guān)文章
定時(shí)備份mysql, 定時(shí)切割nginx access log的方法
定時(shí)備份mysql, 定時(shí)切割nginx access log的方法,需要的朋友可以參考下。2011-09-09mysql獲取字符串長(zhǎng)度函數(shù)(CHAR_LENGTH)
本文介紹一下關(guān)于mysql獲取字符串長(zhǎng)度的方法,希望此教程對(duì)各位同學(xué)會(huì)有所幫助哦。2013-11-11Mysql主從復(fù)制(master-slave)實(shí)際操作案例
這篇文章主要介紹了Mysql主從復(fù)制(master-slave)實(shí)際操作案例,同時(shí)介紹了Mysql grant 用戶授權(quán)的相關(guān)內(nèi)容,需要的朋友可以參考下2014-06-06win10下MySQL 8.0登錄Access denied for user‘root’@‘localhost’ (u
這篇文章主要介紹了win10下MySQL 8.0登錄Access denied for user‘root’@‘localhost’ (using password: YES)問(wèn)題的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-03-03MySQL啟動(dòng)失敗報(bào)錯(cuò):mysqld.service failed to run 
在日常運(yùn)維中,MySQL 作為廣泛應(yīng)用的關(guān)系型數(shù)據(jù)庫(kù),其穩(wěn)定性和可用性至關(guān)重要,然而,有時(shí)系統(tǒng)升級(jí)或配置變更后,MySQL 服務(wù)可能會(huì)出現(xiàn)無(wú)法啟動(dòng)的問(wèn)題,本文針對(duì)某次實(shí)際案例進(jìn)行深入分析和處理,需要的朋友可以參考下2024-12-12SPSS連接mysql數(shù)據(jù)庫(kù)的超詳細(xì)操作教程
小編最近在學(xué)習(xí)SPSS,在為數(shù)據(jù)庫(kù)建立連接時(shí)真的踩了很多坑,這篇文章主要給大家介紹了關(guān)于SPSS連接mysql數(shù)據(jù)庫(kù)的超詳細(xì)操作教程,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-02-02MySQL 參數(shù)相關(guān)概念及查詢更改方法
這篇文章主要介紹了MySQL 參數(shù)相關(guān)概念及查詢更改方法,幫助大家更好的理解和使用MySQL數(shù)據(jù)庫(kù),感興趣的朋友可以了解下2020-09-09MySQL執(zhí)行狀態(tài)查看與分析過(guò)程
這篇文章主要介紹了MySQL執(zhí)行狀態(tài)查看與分析過(guò)程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-07-07