当前位置: 首页 > news >正文

【实战详解】MySQL 8.0递归查询终极教程:附组织架构/分类树完整代码

一、什么是递归查询?

递归查询就像俄罗斯套娃:通过一个查询反复调用自身,逐层解开嵌套的数据结构。

典型应用场景:

  • 组织架构(上下级关系)
  • 分类树(多级分类)
  • 菜单权限树
  • 评论回复嵌套

二、MySQL 8.0+ 的递归查询语法

基础语法结构

WITH RECURSIVE cte_name AS (-- 初始查询(锚点)SELECT ... FROM ...UNION ALL-- 递归部分SELECT ... FROM cte_name, other_tables...WHERE ...
)
SELECT * FROM cte_name;

三、实战示例

示例1:数字序列生成

-- 生成1到10的数字序列
WITH RECURSIVE number_sequence AS (SELECT 1 as n          -- 初始值UNION ALLSELECT n + 1           -- 递归:每次+1FROM number_sequenceWHERE n < 10           -- 终止条件
)
SELECT * FROM number_sequence;

输出:

n
--
1
2
...
10

示例2:组织架构查询 #数据准备

CREATE TABLE employees (id INT PRIMARY KEY,name VARCHAR(50),manager_id INT
);INSERT INTO employees VALUES
(1, 'CEO', NULL),
(2, 'CTO', 1),
(3, '技术总监', 2),
(4, '开发经理', 3),
(5, '开发工程师A', 4),
(6, '开发工程师B', 4),
(7, '产品总监', 2);

#递归查询:找出某员工的所有下属

WITH RECURSIVE employee_tree AS (-- 初始:从CTO开始SELECT id, name, manager_id, 0 as levelFROM employeesWHERE name = 'CTO'UNION ALL-- 递归:逐级向下查找SELECT e.id, e.name, e.manager_id, et.level + 1FROM employees eINNER JOIN employee_tree et ON e.manager_id = et.id
)
SELECT LPAD('', level * 4, ' ') || name as 组织架构,level as 层级
FROM employee_tree;

输出:

组织架构         层级-
CTO            0技术总监    1产品总监    1开发经理 2开发工程师A 3开发工程师B 3

四、分类树查询

数据准备

CREATE TABLE categories (id INT PRIMARY KEY,name VARCHAR(50),parent_id INT
);INSERT INTO categories VALUES
(1, '电子产品', NULL),
(2, '手机', 1),
(3, '电脑', 1),
(4, '智能手机', 2),
(5, '功能手机', 2),
(6, '笔记本电脑', 3),
(7, '台式机', 3),
(8, '游戏本', 6);

查询完整分类路径

WITH RECURSIVE category_path AS (SELECT id,name,parent_id,name as pathFROM categoriesWHERE parent_id IS NULL  -- 根节点UNION ALLSELECT c.id,c.name,c.parent_id,CONCAT(cp.path, ' > ', c.name)FROM categories cINNER JOIN category_path cp ON c.parent_id = cp.id
)
SELECT * FROM category_path;

输出:

id  name        父级ID  path-- - -
1   电子产品    NULL    电子产品
2   手机        1       电子产品 > 手机
3   电脑        1       电子产品 > 电脑
4   智能手机    2       电子产品 > 手机 > 智能手机
5   功能手机    2       电子产品 > 手机 > 功能手机
6   笔记本电脑  3       电子产品 > 电脑 > 笔记本电脑
7   台式机      3       电子产品 > 电脑 > 台式机
8   游戏本      6       电子产品 > 电脑 > 笔记本电脑 > 游戏本

五、评论回复嵌套查询

数据准备

CREATE TABLE comments (id INT PRIMARY KEY,content TEXT,parent_comment_id INT,user_id INT
);INSERT INTO comments VALUES
(1, '这篇文章很棒!', NULL, 101),
(2, '感谢分享', 1, 102),
(3, '我不同意这个观点', 1, 103),
(4, '能详细解释一下吗?', 3, 104),
(5, '请看参考文献', 4, 103);

查询评论树

WITH RECURSIVE comment_tree AS (SELECT id,content,parent_comment_id,user_id,0 as depth,CAST(id AS CHAR(100)) as pathFROM commentsWHERE parent_comment_id IS NULLUNION ALLSELECT c.id,c.content,c.parent_comment_id,c.user_id,ct.depth + 1,CONCAT(ct.path, '-', c.id)FROM comments cINNER JOIN comment_tree ct ON c.parent_comment_id = ct.id
)
SELECT LPAD('', depth * 4, ' ') || content as 评论内容,depth as 嵌套深度
FROM comment_tree
ORDER BY path;

六、高级技巧

  1. 限制递归深度
WITH RECURSIVE limited_tree AS (SELECT id, name, manager_id, 0 as levelFROM employeesWHERE id = 1UNION ALLSELECT e.id, e.name, e.manager_id, lt.level + 1FROM employees eINNER JOIN limited_tree lt ON e.manager_id = lt.idWHERE lt.level < 3  -- 限制最大深度为3层
)
SELECT * FROM limited_tree;
  1. 防止循环引用
WITH RECURSIVE no_cycle AS (SELECT id, name, manager_id, 0 as level,CAST(id AS CHAR(100)) as pathFROM employeesWHERE id = 1UNION ALLSELECT e.id, e.name, e.manager_id, nc.level + 1,CONCAT(nc.path, '-', e.id)FROM employees eINNER JOIN no_cycle nc ON e.manager_id = nc.idWHERE FIND_IN_SET(e.id, nc.path) = 0  -- 防止循环
)
SELECT * FROM no_cycle;
  1. 统计每层数量
WITH RECURSIVE level_count AS (SELECT id, name, manager_id, 0 as levelFROM employeesWHERE manager_id IS NULLUNION ALLSELECT e.id, e.name, e.manager_id, lc.level + 1FROM employees eINNER JOIN level_count lc ON e.manager_id = lc.id
)
SELECT level as 层级,COUNT(*) as 人数
FROM level_count
GROUP BY level
ORDER BY level;

七、性能优化建议

  1. 创建索引
-- 为递归查询的关联字段创建索引
CREATE INDEX idx_manager_id ON employees(manager_id);
CREATE INDEX idx_parent_id ON categories(parent_id);
  1. 控制递归深度
-- 设置最大递归深度
SET SESSION cte_max_recursion_depth = 1000;
  1. 使用 EXISTS 优化
WITH RECURSIVE optimized_tree AS (SELECT id, name, manager_id, 0 as levelFROM employees e1WHERE NOT EXISTS (SELECT 1 FROM employees e2 WHERE e2.manager_id = e1.id)  -- 从叶子节点开始UNION ALLSELECT e.id, e.name, e.manager_id, ot.level + 1FROM employees eINNER JOIN optimized_tree ot ON e.id = ot.manager_id
)
SELECT * FROM optimized_tree;

八、常见错误与解决

❌ 错误:无限递归

-- 错误示例:缺少终止条件
WITH RECURSIVE infinite AS (SELECT 1 as nUNION ALLSELECT n + 1 FROM infinite  -- 没有WHERE条件!
)
SELECT * FROM infinite;

解决: 确保递归部分有明确的终止条件

❌ 错误:循环引用

-- 数据中存在 A→B→A 的循环时
WITH RECURSIVE cycle AS (SELECT id, name, manager_idFROM employeesWHERE id = 1UNION ALLSELECT e.id, e.name, e.manager_idFROM employees eINNER JOIN cycle c ON e.manager_id = c.id
)
SELECT * FROM cycle;  -- 可能无限循环

解决: 使用路径追踪防止循环

九、版本兼容性

| MySQL 版本 | 递归查询支持 | ||--| | 5.7 及以下 | ❌ 不支持 | | 8.0+ | ✅ 支持 |

替代方案(5.7及以下):

  • 应用程序层递归处理
  • 存储过程实现递归逻辑
  • 维护路径字段(如 ​​path = '1/2/3'​​)

十、实用模板

通用递归查询模板

WITH RECURSIVE custom_tree AS (-- 初始查询(锚点成员)SELECT [columns],0 as level,CAST([id_column] AS CHAR(255)) as pathFROM [table_name]WHERE [root_condition]  -- 指定起点UNION ALL-- 递归查询(递归成员)SELECT t.[columns],ct.level + 1,CONCAT(ct.path, '-', t.[id_column])FROM [table_name] tINNER JOIN custom_tree ct ON t.[parent_column] = ct.[id_column]WHERE [termination_condition]  -- 终止条件
)
SELECT * FROM custom_tree;

总结

递归查询 = 初始查询 + 递归部分 + 终止条件

适用场景:

  • ✅ 层次数据结构
  • ✅ 树状关系查询
  • ✅ 路径枚举
  • ❌ 简单线性查询(用普通查询即可)

记住关键点:

  1. 必须使用 ​​WITH RECURSIVE​
  2. 包含 ​​UNION ALL​​ 连接初始和递归部分
  3. 明确的终止条件防止无限递归
  4. MySQL 8.0+ 才支持此功能

通过递归查询,你可以轻松处理复杂的层次数据关系,让数据库帮你完成"一层层剥开"的逻辑! 另外搭配便捷的80kmMYSQL备份工具,可定时备份、异地备份,MYSQL导出导入。可本地连接LINUX里的MYSQL,简单便捷。可以大大地提高工作效率喔。

http://www.dtcms.com/a/495468.html

相关文章:

  • 最新网站开发工具东莞推广外包
  • 双目测距实战3-立体匹配
  • 战斗系统架构:为什么游戏战斗适合ECS架构?
  • 【C语言加油站】C语言文件操作完全指南:feof、ferror与缓冲区机制详解
  • 做seo怎么设计网站响应式网站软件
  • 怎么样建网站卖东西可以入侵的网站
  • 17、Centos9 安装 1Panel
  • Linux学习笔记--GPIO控制器驱动
  • 重庆制作手机网站如何看一个站点是不是有wordpress
  • 网站如何在推广设计公司logo软件
  • 价值1w的数据分析课知识点汇总-excel使用(第一篇)
  • android取消每次u盘插入创建无用(媒体)文件夹
  • 个人如何办网站1m的带宽做网站可以吗
  • 多机部署,负载均衡
  • python通过win32com库调用UDE工具来做开发调试实现自动化源码,以及UDE的知识点介绍
  • 关于Unity中ComputeShader 线程id的理解
  • 幽冥大陆(十六)纸币器BV20识别纸币——东方仙盟筑基期
  • 设计网站的方法做彩票网站需要什么条件
  • Windows 平台 HOOK DWM 桌面管理程序,实现输出变形的桌面图像到显示器
  • Java 大视界 -- Java 大数据在智能电网电力市场交易数据分析与策略制定中的关键作用
  • 安徽和县住房城乡建设局网站wordpress移动端顶部导航栏
  • oracle:判断字段不以开头
  • 学习笔记3-深度学习之logistic回归向量化
  • 哈尔滨网站建设网站优秀个人网站设计欣赏
  • 高辐射环境下AS32S601ZIT2型MCU的抗辐照性能与应用潜力分析
  • 基于STM32F407与FT245R芯片实现USB转并口通信时序控制
  • Retrofit 与 OkHttp 全面解析与实战使用(含封装示例)
  • qiankun知识点
  • 面向接口编程与自上而下的系统设计艺术
  • 数据结构基石:单链表的全面实现、操作详解与顺序表对比