news 2026/6/16 1:55:55

MySQL WITH RECURSIVE 详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MySQL WITH RECURSIVE 详解

目录

  • 一、什么是 WITH RECURSIVE
  • 二、MySQL 从哪个版本开始支持?
  • 三、它解决了什么问题
    • 组织架构
    • 菜单系统
    • 行政区划
    • 评论回复
    • 查询所有子节点
  • 四、WITH RECURSIVE 语法结构
  • 五、递归执行过程
    • 第一步
    • 第二步
    • 第三步
  • 六、WITH RECURSIVE 的组成部分
    • 1. Anchor(锚点)
    • 2. Recursive(递归部分)
    • 3. UNION ALL
  • 七、第一个实战:生成数字序列
    • 生成1~10
  • 八、生成日期序列
  • 九、树形结构实战
    • 部门表
    • 数据结构
  • 十、递归向下查询(查询所有子节点)
  • 十一、增加层级显示
  • 十二、生成完整路径
  • 十三、WITH RECURSIVE 能向上查吗?
  • 十四、向上递归查询祖先节点
  • 十五、向上生成完整路径
  • 十六、避免死循环
  • 十七、递归层数限制
  • 十八、WITH RECURSIVE 使用规则总结
  • 十九、企业开发中的典型应用
      • 组织架构树
      • RBAC权限菜单
      • 评论回复
      • 行政区域
      • 商品分类
  • 二十、面试高频问题
      • Q1:WITH RECURSIVE 从哪个版本开始支持?
      • Q2:WITH 和 WITH RECURSIVE 区别?
      • Q3:能否查询父节点?
      • Q4:为什么推荐 WITH RECURSIVE?
  • 总结

一、什么是 WITH RECURSIVE

WITH RECURSIVE是 MySQL 提供的一种递归公共表表达式(Recursive Common Table Expression,Recursive CTE)

简单理解:

它允许 SQL 自己调用自己,实现递归查询。

类似于 Java 中:

publicvoidtest(Nodenode){test(node.getChild());}

SQL 以前无法直接递归,只能:

  • 多次自关联(JOIN)
  • 应用层循环查询
  • 存储过程递归

WITH RECURSIVE出现后,可以直接在 SQL 中完成树形结构遍历。


二、MySQL 从哪个版本开始支持?

MySQL 从:

MySQL 8.0

开始正式支持:

  • CTE(公共表表达式)
  • Recursive CTE(递归公共表表达式)

即:

WITH...

WITHRECURSIVE...

都是 MySQL 8.0 新增的特性。

MySQL 5.7 及以前:

❌ 不支持


三、它解决了什么问题

开发中经常出现树形结构:

组织架构

董事长 ├── 总经理 │ ├── 技术部 │ └── 财务部 └── 人事部

菜单系统

系统管理 ├── 用户管理 ├── 角色管理 └── 权限管理

行政区划

中国 ├── 北京 ├── 上海 └── 广东 ├── 深圳 └── 广州

评论回复

评论1 ├── 回复1 │ └── 回复2 └── 回复3

以前查询:

查询所有子节点

需要:

select*fromdeptwhereparent_id=1;select*fromdeptwhereparent_idin(...);select*fromdeptwhereparent_idin(...);

不断循环。


现在:

WITHRECURSIVE

一条 SQL 搞定。


四、WITH RECURSIVE 语法结构

标准语法:

WITHRECURSIVE cte_nameAS(-- 初始查询(锚点查询)SELECT...UNIONALL-- 递归查询SELECT...FROMtabletJOINcte_name cON...)SELECT*FROMcte_name;

五、递归执行过程

例如:

WITHRECURSIVE numsAS(SELECT1ASnUNIONALLSELECTn+1FROMnumsWHEREn<5)SELECT*FROMnums;

执行步骤:

第一步

执行锚点查询

SELECT1

结果:

1

第二步

带入递归部分

1+1

得到:

2

第三步

继续递归

3 4 5

结果:

1 2 3 4 5

六、WITH RECURSIVE 的组成部分

必须包含两部分:

1. Anchor(锚点)

递归起点

SELECT1

2. Recursive(递归部分)

不断调用自身

SELECTn+1FROMnumsWHEREn<5

3. UNION ALL

连接两部分

AnchorUNIONALLRecursive

七、第一个实战:生成数字序列

生成1~10

WITHRECURSIVE numsAS(SELECT1ASnumUNIONALLSELECTnum+1FROMnumsWHEREnum<10)SELECT*FROMnums;

结果:

1 2 3 4 5 6 7 8 9 10

八、生成日期序列

生成最近7天

WITHRECURSIVE datesAS(SELECTCURDATE()ASdtUNIONALLSELECTDATE_SUB(dt,INTERVAL1DAY)FROMdatesWHEREdt>CURDATE()-INTERVAL6DAY)SELECT*FROMdates;

结果:

2026-06-15 2026-06-14 2026-06-13 ...

九、树形结构实战

部门表

CREATETABLEdept(idINTPRIMARYKEY,dept_nameVARCHAR(50),parent_idINT);

数据:

1 总公司 NULL 2 技术中心 1 3 财务中心 1 4 开发部 2 5 测试部 2 6 Java组 4 7 前端组 4

数据结构

总公司(1) ├── 技术中心(2) │ ├── 开发部(4) │ │ ├── Java组(6) │ │ └── 前端组(7) │ └── 测试部(5) └── 财务中心(3)

十、递归向下查询(查询所有子节点)

查询部门1下面所有节点

WITHRECURSIVE dept_treeAS(SELECTid,dept_name,parent_id,1levelFROMdeptWHEREid=1UNIONALLSELECTd.id,d.dept_name,d.parent_id,dt.level+1FROMdept dJOINdept_tree dtONd.parent_id=dt.id)SELECT*FROMdept_tree;

结果:

1 总公司 2 技术中心 3 财务中心 4 开发部 5 测试部 6 Java组 7 前端组

十一、增加层级显示

WITHRECURSIVE dept_treeAS(SELECTid,dept_name,parent_id,1levelFROMdeptWHEREid=1UNIONALLSELECTd.id,d.dept_name,d.parent_id,dt.level+1FROMdept dJOINdept_tree dtONd.parent_id=dt.id)SELECTid,dept_name,levelFROMdept_tree;

结果:

id dept_name level 1 总公司 1 2 技术中心 2 3 财务中心 2 4 开发部 3 5 测试部 3 6 Java组 4 7 前端组 4

十二、生成完整路径

很多权限系统都这样做。

例如:

总公司/技术中心/开发部/Java组

SQL:

WITHRECURSIVE dept_treeAS(SELECTid,dept_name,parent_id,dept_nameASpathFROMdeptWHEREid=1UNIONALLSELECTd.id,d.dept_name,d.parent_id,CONCAT(dt.path,'/',d.dept_name)FROMdept dJOINdept_tree dtONd.parent_id=dt.id)SELECT*FROMdept_tree;

结果:

总公司 总公司/技术中心 总公司/技术中心/开发部 总公司/技术中心/开发部/Java组

十三、WITH RECURSIVE 能向上查吗?

答案:

完全可以。

很多人误以为只能向下查。

实际上:

递归方向由 JOIN 条件决定。


十四、向上递归查询祖先节点

例如:

查询 Java组(id=6) 的所有上级。


树:

总公司(1) └── 技术中心(2) └── 开发部(4) └── Java组(6)

SQL:

WITHRECURSIVE parent_treeAS(SELECTid,dept_name,parent_idFROMdeptWHEREid=6UNIONALLSELECTd.id,d.dept_name,d.parent_idFROMdept dJOINparent_tree ptONd.id=pt.parent_id)SELECT*FROMparent_tree;

结果:

6 Java组 4 开发部 2 技术中心 1 总公司

十五、向上生成完整路径

WITHRECURSIVE parent_treeAS(SELECTid,dept_name,parent_id,dept_nameASpathFROMdeptWHEREid=6UNIONALLSELECTd.id,d.dept_name,d.parent_id,CONCAT(d.dept_name,'/',pt.path)FROMdept dJOINparent_tree ptONd.id=pt.parent_id)SELECT*FROMparent_treeORDERBYid;

最终得到:

总公司/技术中心/开发部/Java组

十六、避免死循环

假设数据错误:

1 -> 2 2 -> 3 3 -> 1

形成环:

1 ↓ 2 ↓ 3 ↑ └───

递归将无限执行。


解决方法:

记录访问路径。

WITHRECURSIVE dept_treeAS(SELECTid,parent_id,CAST(idASCHAR(1000))pathFROMdeptWHEREid=1UNIONALLSELECTd.id,d.parent_id,CONCAT(dt.path,',',d.id)FROMdept dJOINdept_tree dtONd.parent_id=dt.idWHEREFIND_IN_SET(d.id,dt.path)=0)SELECT*FROMdept_tree;

十七、递归层数限制

查看:

SHOWVARIABLESLIKE'%recursion%';

通常:

cte_max_recursion_depth = 1000

表示最多递归1000层。


修改:

SETSESSIONcte_max_recursion_depth=5000;

或者:

SETGLOBALcte_max_recursion_depth=5000;

十八、WITH RECURSIVE 使用规则总结

必须:

WITHRECURSIVE nameAS(anchorUNIONALLrecursive)

递归部分必须引用自己

FROMname

必须有终止条件

WHERElevel<100

否则死循环。


推荐使用:

UNIONALL

而不是:

UNION

因为:

UNION

需要去重。

性能更差。


十九、企业开发中的典型应用

组织架构树

总公司 └── 分公司 └── 部门

查询所有下级。


RBAC权限菜单

系统管理 ├── 用户管理 ├── 角色管理 └── 权限管理

加载菜单树。


评论回复

评论 └── 回复 └── 回复

查询完整评论链。


行政区域

中国 └── 广东 └── 深圳

查询省市区。


商品分类

电子产品 └── 手机 └── 安卓手机

查询所有分类。


二十、面试高频问题

Q1:WITH RECURSIVE 从哪个版本开始支持?

MySQL 8.0。


Q2:WITH 和 WITH RECURSIVE 区别?

WITH

普通CTE,不递归。

WITHtAS(SELECT*FROMuser)SELECT*FROMt;

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)

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/16 1:55:27

油桶检测数据集VOC+YOLO格式458张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件)图片数量(jpg文件个数)&#xff1a;458标注数量(xml文件个数)&#xff1a;458标注数量(txt文件个数)&#xff1a;458标注类别数&…

作者头像 李华
网站建设 2026/6/16 1:52:55

告别抢票焦虑!大麦网抢票神器tickets让你的演唱会门票触手可及

告别抢票焦虑&#xff01;大麦网抢票神器tickets让你的演唱会门票触手可及 【免费下载链接】tickets 大麦、大麦网 演唱会抢票软件&#xff0c;一个基于 tauri rust vue 调用接口的抢票软件。 项目地址: https://gitcode.com/gh_mirrors/ti/tickets 还在为心爱歌手的演…

作者头像 李华
网站建设 2026/6/16 1:45:58

阿里云无影Agent开发套件AgentBay对接使用完全指南

阿里云无影Agent开发套件AgentBay&#xff1a;从零到一的对接与使用完全指南 &#x1f4d6; 本文导读 第一章&#xff1a;理解AgentBay——AI Agent的云端基础设施 第二章&#xff1a;对接前的准备工作 第三章&#xff1a;MCP协议接入 第四章&#xff1a;SDK编程接入与Web…

作者头像 李华
网站建设 2026/6/16 1:32:50

【电力系统短期负荷预测】基于ELM、白鲸算法优化ELM、鹭鹰算法优化ELM极限学习机的电力系统短期负荷预测研究附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。 &#x1f34e; 往期回顾关注个人主页&#xff1a;Matlab科研工作室 &#x1f447; 关注我领取海量matlab电子书…

作者头像 李华
网站建设 2026/6/16 1:30:57

芭比裤商家怎么省下拍摄预算?

当一条芭比裤的拍摄预算比面料还贵&#xff0c;你是否想过换个思路&#xff1f;太多商家陷入“视觉军备竞赛”&#xff1a;高薪聘请模特、租赁纯白影棚、后期逐帧修大腿褶皱——单条视频成本能吃掉毛利30%。更扎心的是&#xff0c;用户刷三秒划走&#xff0c;钱白花了。这正是北…

作者头像 李华