MYSQL 8.019 CTE 递归查询怎么解决死循环三种方法

探讨MySQL 8.0引入的CTE递归查询功能,如何避免死循环及数据问题引起的递归异常,介绍使用DISTINCT、LIMIT及设置最大递归深度等方法。

MYSQL CTE 是8.0 引入的SQL 查询的一种功能,通过CTE 可以将复杂的SQL 变得简单,便于分析和查询. 其中CTE 有一种功能递归, 并且牵扯到递归就会有一个问题的提出,就是无限递归的问题.

下面是一个递归死循环的例子

这里先解释一下CTE 递归

1  递归查询至少包含两个子查询, 第一个查询的目的是设置递归的初始值

2  第二个查询成为递归查询,第二个查询调用第一个查询的结果,然后开始循环

之间通过union all 来连接.

递归查询中,当查询的结果不匹配,或超过了递归次数就会停止. 或者在执行是系统发现是死循环则会在设定好的最大cte_max_recursion_depth 后终止查询.

递归查询中出现3636的问题,分为两种

1  数据出现问题 (这是引起递归出现问题的常见原因)

2  SQL 递归的撰写有问题 

根据1 出现问题的概率比较大,并且比较难以排查, 这里就需要在写SQL 的时候,添加一些语句来避免递归出现问题.

1  方法一, 使用distinct ,通过在union 后面添加distinct 来将重复的数据去掉,大部分死循环是因为有重复的数据,这样可以查出数据. 但问题是在 WORKBENCH 中是可以的,但将语句在  MYSQL 程序中是报错的,这点我也没法解释.

2  方法 在MYSQL 8.109 引入了 LIMIT 语句,通过LIMIT 来限制输出数据的数量,投机取巧的避免了部分 3636 的错误

这个方式在workbench 和 MYSQL 命令符下都是OK 的.

实际当中,可能用的最多的是另外一种方式,自动设置让死循环结束

WITH RECURSIVE cte_all AS

(

  SELECT dname AS Child

  FROM cte_test

  WHERE rname='Tim' 

  UNION all

  SELECT r.dname

  FROM cte_test r, cte_all d

  WHERE r.rname=d.Child

  

 )

SELECT /*+ MAX_EXECUTION_TIME(1000) */ * FROM cte_all;

这样的写法在workbench 是OK 的,但在MYSQL 命令行中是还是不可以

当然绕来绕去,最关键的还是修复导致死循环的数据

在修复数据后,在此执行查询,问题解决.

以上几种方法,各有利弊,在软件开发中也有递归函数,当然现在开发的过程中好像在规避递归类似的算法. 但在SQL 的撰写中如果业务逻辑合适, 递归会将SQL 写的比较简单,但需要给定的数据要符合一定的规律,以上的方式均是想通过一定方式来规避由于数据问题,产生的递归问题.

### MySQL 8.0 中 CTE 递归查询的用法 在 MySQL 8.0 版本中引入了公用表表达式(Common Table Expressions, CTE),其中包括 `WITH RECURSIVE` 关键字用于执行递归查询。这种特性允许构建层次结构数据或处理复杂的关系链。 #### 基础语法说明 递归查询的基础结构由两部分组成: - **初始语句**:定义起始条件,通常是一个简单的查询。 - **递归部分**:通过自连接的方式不断扩展结果集直到满足终止条件为止。 具体格式如下所示[^1]: ```sql WITH RECURSIVE 表名 AS ( -- 非递归部分: 定义基础成员 初始语句 UNION ALL -- 递归部分: 添加新成员直至达到结束条件 递归部分语句 ) SELECT * FROM 表名; ``` #### 实际应用案例展示 为了更好地理解如何运用这一功能,在这里提供一个具体的例子来生成一系列连续整数值列表。此操作可以通过下面这段SQL脚本来完成[^4]: ```sql CREATE TEMPORARY TABLE IF NOT EXISTS numbers; WITH RECURSIVE my_cte(n) AS ( SELECT 1 /* 初始化序列的第一个元素 */ UNION ALL /* 合并当前集合与新增加的数据 */ SELECT n + 1 /* 计算下一个数字 */ FROM my_cte /* 自身作为源表进行联合 */ WHERE n < 6 /* 设置循环上限 */ ) INSERT INTO numbers /* 将最终得到的结果存入临时表numbers中 */ SELECT * FROM my_cte; SELECT * FROM numbers; /* 输出全部记录查看效果 */ ``` 上述命令会创建一张名为 `numbers` 的临时表格,并向其中填充从 1 至 6 的自然数列。最后一步则是读取该表的内容以验证预期成果是否达成。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值