最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

MYSQL中WITH RECURSIVE遞歸查詢的實現(xiàn)

 更新時間:2025年08月26日 09:45:53   作者:五月天的尾巴  
MySQL 8.0引入WITH RECURSIVE遞歸查詢,用于處理層級數(shù)據(jù),本文主要介紹了MYSQL中WITH RECURSIVE遞歸查詢的實現(xiàn),具有一定的參考價值,感興趣的可以了解一下

一、前言

MySQL 8.0開始,可以使用WITH RECURSIVE來創(chuàng)建遞歸公用表表達式(Common Table Expressions , CTE)。

遞歸查詢在各種應用場景中都很常見,例如:

  • 組織架構查詢: 獲取公司內(nèi)部的組織結(jié)構信息,從CEO到普通員工的層級關系。
  • 產(chǎn)品分類查詢: 從頂級分類到子分類的層級查找。
  • 目錄結(jié)構查詢: 在文件系統(tǒng)中,從根目錄到子目錄的路徑查找。

二、語法

WITH RECURSIVE cte_name (column_list) AS (
	SELECT
		initial_query -- 初始查詢
	UNION [ALL]
		recursive_query  -- 遞歸查詢
)
SELECT * FROM cte_name;

其中:

  • CTE 名稱(cte_name)用于標識遞歸查詢的臨時結(jié)果集。
  • 列名列表(column_list)定義了 CTE 結(jié)果集中包含的列及其名稱。
  • 初始查詢(initial_query)提供遞歸過程的起點,即第一次迭代時使用的數(shù)據(jù)。
  • 遞歸部分(遞歸子查詢)定義了如何將前一次迭代的結(jié)果作為輸入,計算出下一次迭代的數(shù)據(jù)。
  • recursive_query:表示遞歸查詢語句,應當與column_list中的列名對應。
  • SELECT * FROM cte_name:表示最終返回的查詢結(jié)果集,可以通過cte_name查詢表中的列名進行指定。

1.遞歸查詢的結(jié)構
遞歸查詢通常由兩部分構成:初始化查詢(非遞歸部分)遞歸子查詢(遞歸部分)。

  • 初始化查詢: 定義遞歸開始時的基礎數(shù)據(jù)集,通常是與遞歸邏輯相關的最頂層數(shù)據(jù)或邊界條件。
  • 遞歸子查詢: 定義如何根據(jù)前一次迭代的結(jié)果生成下一次迭代的數(shù)據(jù)。遞歸子查詢通常包含對自身 CTE 名稱的引用,以遞歸地應用相同的操作。

2.連接操作符:

  • 遞歸查詢的初始化查詢遞歸查詢通常通過 UNIONUNION ALL 連接起來,形成一個完整的遞歸查詢表達式。
  • UNION 會去除結(jié)果集中的重復行,而 UNION ALL 不會去除重復,根據(jù)實際需求選擇合適的連接操作符。

3.終止條件

  • 遞歸查詢必須有一個明確的終止條件,否則會無限循環(huán)下去。終止條件通常隱含在遞歸子查詢的 WHERE 子句或其他邏輯中,當滿足特定條件時,不再產(chǎn)生新的結(jié)果。

三、示例

通過以下目錄樹示例查詢父節(jié)點、子節(jié)點、及全鏈路等信息。

3.1、創(chuàng)建測試表和數(shù)據(jù)

CREATE TABLE tree_table (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    parent_id INT
);

INSERT INTO tree_table (id, name, parent_id) VALUES
(1, 'A', NULL),
(2, 'B', 1),
(3, 'C', 1),
(4, 'D', 2),
(5, 'E', 3);
(6, 'F', 3);
(7, 'G', 5);

3.2、查詢所有子節(jié)點(以 id=1 為例)

WITH RECURSIVE cte AS (
    SELECT id, parent_id, name
    FROM tree_table
    WHERE id = 1
    UNION ALL
    SELECT t.id, t.parent_id, t.name
    FROM tree_table t
    INNER JOIN cte ON t.parent_id = cte.id
)
SELECT * FROM cte;

結(jié)果:

3.3、查詢所有父節(jié)點(以 id=5 為例)

WITH RECURSIVE cte AS (
    SELECT id, parent_id, name
    FROM tree_table
    WHERE id = 5
    UNION ALL
    SELECT t.id, t.parent_id, t.name
    FROM tree_table t
    INNER JOIN cte ON t.id = cte.parent_id
)
SELECT * FROM cte;

注意:子節(jié)點與父節(jié)點的區(qū)別在于join的關聯(lián)條件on的不同。

結(jié)果:

3.4、查詢所有子節(jié)點(向下遞歸)并顯示全鏈路路徑及層級

查詢節(jié)點下的所有子節(jié)點,并且可以看到全鏈路及層級,如A->B->C

WITH RECURSIVE cte AS (
    SELECT
        id,parent_id, name,
        name AS path,   -- 初始路徑
        1 AS level      -- 起始層級
    FROM tree_table
    WHERE id = 1  -- 查詢ID=1的所有子節(jié)點
    UNION ALL
    SELECT
        t.id,t.parent_id,t.name,
        CONCAT(cte.path, '->', t.name),  -- 路徑拼接
        cte.level + 1                    -- 層級遞增
    FROM tree_table t
    INNER JOIN cte ON t.parent_id = cte.id
)
SELECT * FROM cte;

結(jié)果如下:

3.5、查詢所有父節(jié)點(向上遞歸)并顯示全鏈路路徑及層級

查詢節(jié)點的所有父節(jié)點,并且可以看到全鏈路及層級,如A->B->C

WITH RECURSIVE cte AS (
    SELECT
        id, parent_id, name,
        CAST(name AS CHAR(255)) AS path,  -- 路徑初始化
        1 AS level                        -- 起始層級
    FROM tree_table
    WHERE id = 6  -- 查詢ID=6的所有父節(jié)點
    UNION ALL
    SELECT
        t.id, t.parent_id, t.name,
        CONCAT(t.name, '->', cte.path),  -- 向前拼接路徑
        cte.level + 1                    -- 層級遞增
    FROM tree_table t
    INNER JOIN cte ON t.id = cte.parent_id
)
SELECT * FROM cte
ORDER BY level ASC;  -- 按層級升序排列

結(jié)果如下:

3.6、高級功能:雙向遞歸查詢(同時獲取祖先和后代)

-- 獲取ID=5的所有祖先和后代
WITH RECURSIVE
down AS ( /* 向下遞歸獲取后代 */
    SELECT id, parent_id, name, name AS path, 1 AS level
    FROM tree_table WHERE id = 5
    UNION ALL
    SELECT t.id, t.parent_id, t.name,
           CONCAT(down.path, '->', t.name),
           down.level + 1
    FROM tree_table t
    INNER JOIN down ON t.parent_id = down.id
),
up AS ( /* 向上遞歸獲取祖先 */
    SELECT id, parent_id, name, name AS path, 1 AS level
    FROM tree_table WHERE id = 5
    UNION ALL
    SELECT t.id, t.parent_id, t.name,
           CONCAT(t.name, '->', up.path),
           up.level + 1
    FROM tree_table t
    INNER JOIN up ON t.id = up.parent_id
)
SELECT * FROM up WHERE id != 5  -- 排除重復的當前節(jié)點
UNION ALL
SELECT * FROM down;

結(jié)果如下:

上圖示例中同時查詢了父節(jié)點與子節(jié)點,可能從返回結(jié)果中不能區(qū)別出哪些是父節(jié)點哪些是子節(jié)點。這里改造一下:

-- 獲取ID=5的所有祖先和后代
WITH RECURSIVE
down AS ( /* 向下遞歸獲取后代 */
    SELECT id, parent_id, name, name AS path, 1 AS level,'down' as type
    FROM tree_table WHERE id = 5
    UNION ALL
    SELECT t.id, t.parent_id, t.name,
           CONCAT(down.path, '->', t.name),
           down.level + 1,
           'down' as type
    FROM tree_table t
    INNER JOIN down ON t.parent_id = down.id
),
up AS ( /* 向上遞歸獲取祖先 */
    SELECT id, parent_id, name, name AS path, 1 AS level,'up' as type
    FROM tree_table WHERE id = 5
    UNION ALL
    SELECT t.id, t.parent_id, t.name,
           CONCAT(t.name, '->', up.path),
           up.level + 1,
           'up' as type
    FROM tree_table t
    INNER JOIN up ON t.id = up.parent_id
)
SELECT * FROM up  WHERE id != 5  -- 排除重復的當前節(jié)點
UNION ALL
SELECT * FROM down;

添加type字段區(qū)分父節(jié)點、子節(jié)點。

四、擴展

4.1、注意事項:

  1. 遞歸深度限制: MySQL 默認遞歸深度為 1000,超限會報錯。可通過設置會話變量調(diào)整:
SET SESSION cte_max_recursion_depth = 10000; -- 修改遞歸深度
  1. 避免死循環(huán): 確保數(shù)據(jù)中沒有循環(huán)引用(如 A→B→A)。

  2. 性能: 大數(shù)據(jù)量時確保 parent_id 字段有索引:

CREATE INDEX idx_parent_id ON tree_table(parent_id);
  1. 路徑長度限制:
CAST(name AS CHAR(255))  -- 根據(jù)實際需要調(diào)整長度

4.2、避免死循環(huán)

避免死循環(huán): 確保數(shù)據(jù)中沒有循環(huán)引用(如 A→B→A

如果遇到循環(huán)引用會導致遞歸查詢無限循環(huán)查詢,從而引發(fā)數(shù)據(jù)庫異常報錯。

解決方法:

  • 方法一:避免死循環(huán),確保數(shù)據(jù)中沒有循環(huán)引用(如 A→B→A
  • 方法二:限制遞歸層級,查詢時設置遞歸層級,如小于10級

4.3、結(jié)果排序技巧

  • 按層級排序:ORDER BY level ASC
  • 按路徑排序:ORDER BY full_path ASC
  • 按樹形結(jié)構排序:
ORDER BY 
  LENGTH(full_path) - LENGTH(REPLACE(full_path, '->', '')),
  full_path

到此這篇關于MYSQL中WITH RECURSIVE遞歸查詢的實現(xiàn)的文章就介紹到這了,更多相關MYSQL WITH RECURSIVE遞歸查詢內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

最新評論

新兴县| 金华市| 义乌市| 舒城县| 广平县| 吉水县| 林周县| 双桥区| 巫溪县| 凤凰县| 宁城县| 沭阳县| 安宁市| 黄山市| 墨江| 高青县| 宁化县| 黑河市| 紫阳县| 安福县| 邵阳县| 溆浦县| 武鸣县| 阳江市| 湖南省| 三明市| 台中市| 澄江县| 清水县| 大化| 惠州市| 岳阳县| 启东市| 四子王旗| 恩施市| 民权县| 东阿县| 大丰市| 莲花县| 同仁县| 宁陕县|