最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
MySQLWithRecursive与语法结构详解(最新推荐)
时间:2026-06-17 08:46:55 编辑:袖梨 来源:一聚教程网
一、什么是 WITH RECURSIVE
WITH RECURSIVE 是 MySQL 提供的一种递归公共表表达式(Recursive Common Table Expression,Recursive CTE)。

简单理解:
它允许 SQL 自己调用自己,实现递归查询。
类似于 Java 中:
public void test(Node node){ test(node.getChild());}SQL 以前无法直接递归,只能:
- 多次自关联(JOIN)
- 应用层循环查询
- 存储过程递归
而 WITH RECURSIVE 出现后,可以直接在 SQL 中完成树形结构遍历。
二、MySQL 从哪个版本开始支持?
MySQL 从:
MySQL 8.0
开始正式支持:
- CTE(公共表表达式)
- Recursive CTE(递归公共表表达式)
即:
WITH ...
和
WITH RECURSIVE ...
都是 MySQL 8.0 新增的特性。
MySQL 5.7 及以前:
❌ 不支持
三、它解决了什么问题
开发中经常出现树形结构:
组织架构
董事长 ├── 总经理 │ ├── 技术部 │ └── 财务部 └── 人事部
菜单系统
系统管理 ├── 用户管理 ├── 角色管理 └── 权限管理
行政区划
中国 ├── 北京 ├── 上海 └── 广东 ├── 深圳 └── 广州
评论回复
评论1 ├── 回复1 │ └── 回复2 └── 回复3
以前查询:
查询所有子节点
需要:
select * from dept where parent_id=1;select * from dept where parent_id in(...);select * from dept where parent_id in(...);
不断循环。
现在:
WITH RECURSIVE
一条 SQL 搞定。
四、WITH RECURSIVE 语法结构
标准语法:
WITH RECURSIVE cte_name AS ( -- 初始查询(锚点查询) SELECT ... UNION ALL -- 递归查询 SELECT ... FROM table t JOIN cte_name c ON ...)SELECT * FROM cte_name;
五、递归执行过程
例如:
WITH RECURSIVE nums AS ( SELECT 1 AS n UNION ALL SELECT n + 1 FROM nums WHERE n < 5)SELECT * FROM nums;
执行步骤:
第一步
执行锚点查询
SELECT 1
结果:
1
第二步
带入递归部分
1 + 1
得到:
2
第三步
继续递归
345
结果:
12345
六、WITH RECURSIVE 的组成部分
必须包含两部分:
1. Anchor(锚点)
递归起点
SELECT 1
2. Recursive(递归部分)
不断调用自身
SELECT n+1FROM numsWHERE n<5
3. UNION ALL
连接两部分
AnchorUNION ALLRecursive
七、第一个实战:生成数字序列
生成1~10
WITH RECURSIVE nums AS ( SELECT 1 AS num UNION ALL SELECT num + 1 FROM nums WHERE num < 10)SELECT * FROM nums;
结果:
12345678910
八、生成日期序列
生成最近7天
WITH RECURSIVE dates AS ( SELECT CURDATE() AS dt UNION ALL SELECT DATE_SUB(dt,INTERVAL 1 DAY) FROM dates WHERE dt > CURDATE()-INTERVAL 6 DAY)SELECT * FROM dates;
结果:
2026-06-152026-06-142026-06-13...
九、树形结构实战
部门表
CREATE TABLE dept( id INT PRIMARY KEY, dept_name VARCHAR(50), parent_id INT);
数据:
1 总公司 NULL2 技术中心 13 财务中心 14 开发部 25 测试部 26 Java组 47 前端组 4
数据结构
总公司(1)├── 技术中心(2)│ ├── 开发部(4)│ │ ├── Java组(6)│ │ └── 前端组(7)│ └── 测试部(5)└── 财务中心(3)
十、递归向下查询(查询所有子节点)
查询部门1下面所有节点
WITH RECURSIVE dept_tree AS ( SELECT id, dept_name, parent_id, 1 level FROM dept WHERE id = 1 UNION ALL SELECT d.id, d.dept_name, d.parent_id, dt.level + 1 FROM dept d JOIN dept_tree dt ON d.parent_id = dt.id)SELECT *FROM dept_tree;
结果:
1 总公司2 技术中心3 财务中心4 开发部5 测试部6 Java组7 前端组
十一、增加层级显示
WITH RECURSIVE dept_tree AS ( SELECT id, dept_name, parent_id, 1 level FROM dept WHERE id=1 UNION ALL SELECT d.id, d.dept_name, d.parent_id, dt.level+1 FROM dept d JOIN dept_tree dt ON d.parent_id=dt.id)SELECT id, dept_name, levelFROM dept_tree;
结果:
id dept_name level1 总公司 12 技术中心 23 财务中心 24 开发部 35 测试部 36 Java组 47 前端组 4
十二、生成完整路径
很多权限系统都这样做。
例如:
总公司/技术中心/开发部/Java组
SQL:
WITH RECURSIVE dept_tree AS ( SELECT id, dept_name, parent_id, dept_name AS path FROM dept WHERE id=1 UNION ALL SELECT d.id, d.dept_name, d.parent_id, CONCAT(dt.path,'/',d.dept_name) FROM dept d JOIN dept_tree dt ON d.parent_id=dt.id)SELECT *FROM dept_tree;
结果:
总公司总公司/技术中心总公司/技术中心/开发部总公司/技术中心/开发部/Java组
十三、WITH RECURSIVE 能向上查吗?
答案:
完全可以。
很多人误以为只能向下查。
实际上:
递归方向由 JOIN 条件决定。
十四、向上递归查询祖先节点
例如:
查询 Java组(id=6) 的所有上级。
树:
总公司(1)└── 技术中心(2) └── 开发部(4) └── Java组(6)
SQL:
WITH RECURSIVE parent_tree AS ( SELECT id, dept_name, parent_id FROM dept WHERE id = 6 UNION ALL SELECT d.id, d.dept_name, d.parent_id FROM dept d JOIN parent_tree pt ON d.id = pt.parent_id)SELECT *FROM parent_tree;
结果:
6 Java组4 开发部2 技术中心1 总公司
十五、向上生成完整路径
WITH RECURSIVE parent_tree AS ( SELECT id, dept_name, parent_id, dept_name AS path FROM dept WHERE id=6 UNION ALL SELECT d.id, d.dept_name, d.parent_id, CONCAT(d.dept_name,'/',pt.path) FROM dept d JOIN parent_tree pt ON d.id=pt.parent_id)SELECT *FROM parent_treeORDER BY id;
最终得到:
总公司/技术中心/开发部/Java组
十六、避免死循环
假设数据错误:
1 -> 22 -> 33 -> 1
形成环:
1↓2↓3↑└───
递归将无限执行。
解决方法:
记录访问路径。
WITH RECURSIVE dept_tree AS ( SELECT id, parent_id, CAST(id AS CHAR(1000)) path FROM dept WHERE id=1 UNION ALL SELECT d.id, d.parent_id, CONCAT(dt.path,',',d.id) FROM dept d JOIN dept_tree dt ON d.parent_id=dt.id WHERE FIND_IN_SET(d.id,dt.path)=0)SELECT *FROM dept_tree;
十七、递归层数限制
查看:
SHOW VARIABLES LIKE '%recursion%';
通常:
cte_max_recursion_depth = 1000
表示最多递归1000层。
修改:
SET SESSION cte_max_recursion_depth = 5000;
或者:
SET GLOBAL cte_max_recursion_depth = 5000;
十八、WITH RECURSIVE 使用规则总结
必须:
WITH RECURSIVE name AS( anchor UNION ALL recursive)
递归部分必须引用自己
FROM name
必须有终止条件
WHERE level < 100
否则死循环。
推荐使用:
UNION ALL
而不是:
UNION
因为:
UNION
需要去重。
性能更差。
十九、企业开发中的典型应用
组织架构树
总公司 └── 分公司 └── 部门
查询所有下级。
RBAC权限菜单
系统管理 ├── 用户管理 ├── 角色管理 └── 权限管理
加载菜单树。
评论回复
评论 └── 回复 └── 回复
查询完整评论链。
行政区域
中国 └── 广东 └── 深圳
查询省市区。
商品分类
电子产品 └── 手机 └── 安卓手机
查询所有分类。
二十、面试高频问题
Q1:WITH RECURSIVE 从哪个版本开始支持?
MySQL 8.0。
Q2:WITH 和 WITH RECURSIVE 区别?
WITH
普通CTE,不递归。
WITH t AS( SELECT * FROM user)SELECT * FROM t;
WITH RECURSIVE
支持递归调用自身。
Q3:能否查询父节点?
可以。
改变 JOIN 方向即可。
向下:
d.parent_id = tree.id
向上:
d.id = tree.parent_id
Q4:为什么推荐 WITH RECURSIVE?
相比循环查询:
- SQL更简洁
- 只访问一次数据库
- 性能更好
- 天然支持树形结构
总结
WITH RECURSIVE 是 MySQL 8.0 引入的递归查询能力,通过“锚点查询 + UNION ALL + 递归查询”的方式,可以优雅地处理组织架构、菜单树、评论树、行政区划、商品分类等层级数据,既能向下查询所有子孙节点,也能向上查询所有祖先节点,是现代 MySQL 树形数据查询的首选方案。
参考:
mysql递归查询语法WITH RECURSIVE
MySQL RECURSIVE Clauses
MySQL | Recursive CTE (Common Table Expressions)
相关文章
- 时隙之旅ssr最强阵容怎么搭配 06-18
- 文心一言企业版收费说明:费用、权限与使用场景 06-18
- 有php源码怎么打开:用编辑器打开已有PHP源码教程【教程】 06-18
- 文心一言企业版功能说明:权限、费用与团队协作场景 06-18
- 剪映怎样剪辑视频片头-剪映如何剪辑视频片头 06-18
- 蚂蚁庄园今天正确答题6月18日 蚂蚁庄园的今天正确答案是什么呢 06-18