MySQL8.0-CTE递归查询(避免死循环)
TSQL脚本能实现递归查询,用户使用共用表表达式 CTE(Common Table Expression),只需要编写少量的代码,就能实现递归查询。
本文详细介绍CTE递归调用的特性和使用示例,递归查询主要用于层次结构的查询,从叶级(Leaf Level)向顶层(Root Level)查询,或从顶层向叶级查询,或递归的路径(Path)。
一、递归查询原理
递归调用是指自己调用自己,使用CTE实现递归查询必须满足三个条件:初始条件,递归调用表达式,终止条件。
CTE 递归查询的伪代码如下:
WITH recursive cte_name ( column_name [,...n]) AS (
CTE_query_definition
UNION ALL
CTE_query_definition
)
SELECT * FROM cte_name
1,递归查询至少包含两个子查询:
第一个子查询称作定点(Anchor)子查询:定点查询只是一个返回有效表的查询,用于设置递归的初始值;
第二个子查询称作递归子查询:该子查询调用CTE名称,触发递归查询,实际上是递归子查询调用递归子查询;
两个子查询使用union all,求并集;
2,CTE的递归终止条件
递归查询没有显式的递归终止条件,只有当递归子查询返回空结果集(没有数据行返回)或是超出了递归次数的最大限制时,才停止递归。
默认的递归查询次数是100,可以使用查询提示(hint):MAXRECURSION 控制递归的最大次数:OPTION( MAXRECURSION 16);如果允许无限制的递归次数,使用查询提示:option(maxrecursion 0);当递归查询达到指定或默认的 MAXRECURSION 数量限制时,SQL Server将结束查询并返回错误,如下:
The statement terminated. The maximum recursion 10 has been exhausted before statement completion.
事务执行失败,该事务包含的所有操作都被回滚。在产品环境中,慎用maxrecursion 查询提示,推荐通过 where 条件限制递归的次数。
3,递归步骤
step1:定点子查询设置CTE的初始值,即CTE的初始值Set0;
递归调用的子查询过程:递归子查询调用递归子查询;
step2:递归子查询第一次调用CTE名称,CTE名称是指CTE的初始值Set0,第一次执行递归子查询之后,CTE名称是指结果集Set1;
step3:递归子查询第二次调用CTE名称,CTE名称是指Set1,第二次执行递归子查询之后,CTE名称是指结果集Set2;
step4:在第N次执行递归子查询时,CTE名称是指Set(N-1),递归子查询都引用前一个递归子查询的结果集;
Step5:如果递归子查询返回空数据行,或超出递归次数的最大限制,停止递归;
二、递归查询演示
创建表:
CREATE TABLE `test_child_parent` (
`id` int NOT NULL,
`name` varchar(255) DEFAULT NULL,
`parent_id` int DEFAULT NULL,
`parent_name` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
插入数据:
INSERT INTO `test_child_parent`(`id`, `name`, `parent_id`, `parent_name`) VALUES (1, '一级', NULL, NULL);
INSERT INTO `test_child_parent`(`id`, `name`, `parent_id`, `parent_name`) VALUES (2, '二级', 1, '一级');
INSERT INTO `test_child_parent`(`id`, `name`, `parent_id`, `parent_name`) VALUES (3, '二级', 1, '一级');
INSERT INTO `test_child_parent`(`id`, `name`, `parent_id`, `parent_name`) VALUES (4, '三级', 2, '二级');
INSERT INTO `test_child_parent`(`id`, `name`, `parent_id`, `parent_name`) VALUES (5, '四级', 3, '二级');
INSERT INTO `test_child_parent`(`id`, `name`, `parent_id`, `parent_name`) VALUES (6, '五级', 5, '四级');
INSERT INTO `test_child_parent`(`id`, `name`, `parent_id`, `parent_name`) VALUES (7, '五级', 5, '四级');
INSERT INTO `test_child_parent`(`id`, `name`, `parent_id`, `parent_name`) VALUES (8, '五级', 5, '四级');
查询数据:
select * from test_child_parent ;

向上递归查询
with recursive temp as (
select * from test_child_parent p where id = 8
union all
select t.* from test_child_parent t inner join temp t2 on t2.parent_id = t.id
)
select * from temp;
查询结果:

向下递归:
--查询下游节点(包含自己)
with recursive temp as (
select * from test_child_parent p where id = 3
union all
select t.* from test_child_parent t inner join temp t2 on t2.id = t.parent_id
)
select * from temp ;
查询结果:

三、特殊情况(死循环)
如果数据出现异常,比如 A -> B , B -> C , C -> A ,出现这样的情况,查询时就会出现死循环。
INSERT INTO `test_child_parent`(`id`, `name`, `parent_id`, `parent_name`) VALUES (3, '二级', 8, '五级');
这样再查询时就会报错:
Recursive query aborted after 1001 iterations. Try increasing @@cte_max_recursion_depth to a larger value.
遇到这种死循环的递归查询,如何避免呢?
在MYSQL 8.109 引入了 LIMIT 语句,通过LIMIT 来限制输出数据的数量。
with recursive temp as (
select * from test_child_parent p where id = 8
union all
select t.* from test_child_parent t inner join temp t2 on t2.parent_id = t.id limit 10
)
select * from temp ;
查询结果:

此时可以很快查询出结果,但是存在如下问题:
1、limit 返回行数,需要合理设置,否则返回的数据可以缺少;
2、查询的结果是重复的,需要进行去重处理,比如:在查询时加上distinct,或者使用group by 等方式。
with recursive temp as (
select * from test_child_parent p where id = 8
union all
select t.* from test_child_parent t inner join temp t2 on t2.parent_id = t.id limit 1000
)
select distinct * from temp ;
MySQL8.0-CTE递归查询(避免死循环)的更多相关文章
- Mysql8.0新特性【详细版本】
1. 账户与安全 用户创建与授权 之前:创建用户并授权 1 grant all privileges on *.* to 'myuser'@'%' identified by '3edc#EDC'; ...
- SQL Server 2005中的CTE递归查询得到一棵树
感觉这个CTE递归查询蛮好用的,先举个例子: use City; go create table Tree ( ID int identity(1,1) primary key not null, N ...
- SQL Server CTE 递归查询全解
在TSQL脚本中,也能实现递归查询,SQL Server提供CTE(Common Table Expression),只需要编写少量的代码,就能实现递归查询,本文详细介绍CTE递归调用的特性和使用示例 ...
- SQL Server CTE 递归查询全解 -- 转 学习
在TSQL脚本中,也能实现递归查询,SQL Server提供CTE(Common Table Expression),只需要编写少量的代码,就能实现递归查询,本文详细介绍CTE递归调用的特性和使用示例 ...
- SQL Server CTE 递归查询全解(转载)
在TSQL脚本中,也能实现递归查询,SQL Server提供CTE(Common Table Expression),只需要编写少量的代码,就能实现递归查询,本文详细介绍CTE递归调用的特性和使用示例 ...
- CTE 递归查询全解
TSQL脚本能实现递归查询,用户使用共用表表达式 CTE(Common Table Expression),只需要编写少量的代码,就能实现递归查询.本文详细介绍CTE递归调用的特性和使用示例,递归查询 ...
- SQLServer2005中的CTE递归查询得到一棵树
最近研究了一下CTE递归查询,感觉这个CTE递归查询蛮好用的,在网上找到了一个比较好的例子,测试例子如下 use City; go create table Tree ( ID ,) primary ...
- 利用临时表实现CTE递归查询
一.CTE递归查询简介 --CTE递归查询终止条件在TSQL脚本中,也能实现递归查询,SQL Server提供CTE(Common Table Expression),只需要编写少量的代码,就能实现递 ...
- MySQL8.0新特性实验1
Server层,选项持久化 mysql> show variables like '%max_connections%';+------------------------+-------+| ...
- 跨时代的MySQL8.0新特性解读
目录 MySQL发展历程 MySQL8.0新特性 秒级加列 性能提升 文档数据库 SQL增强 共用表表达式(CTEs) 不可见索引(Invisible Indexes) 降序索引(Descending ...
随机推荐
- C#使用ParseExact方法将字符串转化为日期格式
private void btn_Convert_Click(object sender, EventArgs e) { #region 针对Windows 7系统 string s = string ...
- 基于java+springboot的旅游信息网站、旅游景区门票管理系统
该系统是基于java+springboot开发的旅游景区门票管理系统.是给师弟开发的大四实习作品.学习过程中,遇到问题可以咨询github作者. 演示地址 前台地址: http://travel.gi ...
- java中native源码查找方法
以Object的hashCode()方法为例: 1. 下载openjdk源码或从github中查找,这里以github中查找为例:2. GitHub中查找https://github.com/bpup ...
- electron打包,使用electron-packager
构建项目可以使用electron-forge构建,但是这个东西打包比较坑,mac运行报错,win下会有缓存机制,也就是热更新无效 所以选择使用electron-packager打包 sudo npm ...
- GitLab的安装、配置、使用
前言 上周去参与"中国数字经济创新发展大会"了,然后又忙新项目的事情,博客又有一段时间没有更新,今天周一事情比较少,立刻开始写文,最近有挺多值得记录的东西~ 进入正文,最近我们搭了 ...
- MySQL调优学习-快速获取占用CPU较高的SQL语句
MySQL调优学习-快速获取占用CPU较高的SQL语句 背景 早上突然发现一个MySQL数据库的CPU使用率居高 因为是一个混布的环境上面还有一个redis 怕影响业务就上去像查看一下具体是何种原因导 ...
- process-exporter 监控linux机器进程使用情况
process-exporter 监控linux机器进程使用情况 背景 前期一直想进行 关于 IP地址的来源和目的地的监控 但是耗费了很多精力都没有搞定. 感觉应该去偷师一下安全监控软件的使用方式. ...
- [转帖]美国出口管制条例(EAR)简介
https://zhuanlan.zhihu.com/p/87962305 第一节.美国出口管制法律体系 下述一系列法律.法规及规则,构成美国完整的出口管理制度,是美国各相关执法部门执法的主要法律依据 ...
- [转帖]Oracle入门精读28-字符集 AL32UTF8与UTF8
字符(Character) 字符是各种文字和符号的总称,包括各国家文字.标点符号.图形符号.数字等. 字符编码(Character Encoding) 是一套法则,使用该法则能够对自然语言的字符的一个 ...
- Sysbench简单测试数据库性能
摘要 先进行了一个PG数据库的测试. Mysql数据库的测试稍后跟上. 紧接着上一篇的安装, 部分文件可能需要特定路径才可以. sysbench 测试的说明 一个参数 这里稍微说一下参数的问题 sys ...