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

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

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

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

相關(guān)文章

最新評(píng)論