欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

MySQL中普通CTE和遞歸CTE的順序問題小結(jié)

 更新時(shí)間:2025年08月26日 10:10:53   作者:五月天的尾巴  
本文主要介紹了MySQL 中普通 CTE 和遞歸 CTE 的順序問題,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

本文主要探討mysqlwith普通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 aswith 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)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論