MySql 实现递归with recursive
MySQL版本8.0.21-2
递归方式生成一个临时表tmp,且填充了10条数据
WITH recursive tmp ( a, b ) AS (SELECT1,'2022-01-01' UNION ALLSELECTROUND( RAND()* 10 ),b - INTERVAL ROUND( RAND() * 1000 ) DAY FROMTMP LIMIT 10 ) TABLE tmp;
以列a递增
WITH recursive tmp ( a, b ) AS (SELECT 1, '2022-01-01' UNION ALL SELECT a + 1, b - INTERVAL ROUND( RAND() * 1000 ) DAY FROM TMP LIMIT 10 ) TABLE tmp;
输出1~n:
WITH RECURSIVE cte (n) AS
(SELECT 1UNION ALLSELECT n + 1 FROM cte LIMIT 10
)
SELECT * FROM cte;
#可将`LIMIT`改成`WHERE n < 10`
+----+
| n |
+----+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
| 10 |
+----+
输出n!,即n的阶乘:
WITH RECURSIVE cte ( n, m ) AS ( SELECT 1, 1 UNION ALL SELECT n + 1, ( n + 1 ) * m FROM cte WHERE n < 10 ) SELECT
*
FROMcte;
#或者
WITH RECURSIVE cte AS (SELECT1 AS n,1 AS m UNION ALLSELECTn + 1,( n + 1 ) * m FROMcte WHEREn < 10 ) SELECT*
FROMcte;
+----+---------+
| n | m |
+----+---------+
| 1 | 1 |
| 2 | 2 |
| 3 | 6 |
| 4 | 24 |
| 5 | 120 |
| 6 | 720 |
| 7 | 5040 |
| 8 | 40320 |
| 9 | 362880 |
| 10 | 3628800 |
+----+---------+
输出前n个数的和:
WITH RECURSIVE cte AS ( SELECT 1 AS n, 1 AS sum UNION ALL SELECT n + 1, sum + n + 1 FROM cte WHERE n < 10 ) SELECT
*
FROMcte;
+----+-----+
| n | sum |
+----+-----+
| 1 | 1 |
| 2 | 3 |
| 3 | 6 |
| 4 | 10 |
| 5 | 15 |
| 6 | 21 |
| 7 | 28 |
| 8 | 36 |
| 9 | 45 |
| 10 | 55 |
+----+-----+
简单递归用法:
首先我们引出一个问题: 什么叫做递归?
递归:给定函数初始条件,然后反复调用自身直到终止条件.
例子1:递归得到依次递增的序列:
WITH RECURSIVE cte (n) AS
(SELECT 1UNION ALLSELECT n + 1 FROM cte WHERE n < 5
)
SELECT * FROM cte;
+---+
| n |
+---+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
+---+
官方文档中对于这个写法的解释:
At each iteration, that SELECT produces a row with a new value one greater than the value of n from the previous row set. The first iteration operates on the initial row set (1) and produces 1+1=2; the second iteration operates on the first iteration’s row set (2) and produces 2+1=3; and so forth. This continues until recursion ends, which occurs when n is no longer less than 5.
也就是说,一个with recursive 由两部分组成。第一部分是非递归部分(union all上方),第二部分是递归部分(union all下方)。递归部分第一次进入的时候使用非递归部分传递过来的参数。也就是第一行的数据值,进而得到第二行数据值。然后根据第二行数据值得到第三行数据值。
例子2:递归得到不断复制的字符串
这里的as表示列名,表示说这个CTE有两个列,也可以写为with cte(n,str) as (subquery)
WITH RECURSIVE cte AS
(SELECT 1 AS n, 'abc' AS strUNION ALLSELECT n + 1, CONCAT(str, str) FROM cte WHERE n < 3
)
SELECT * FROM cte;
结果:
+---+-----+
| n | str |
+---+-----+
| 1 | abc |
| 2 | abc |
| 3 | abc |
+---+-----+
或者报错:‘Data too long for column ‘str’ at row 1’
这里的话concat是每一次都连接一个str,这个str来自上一行的结果,但是最终输出却是每一行都没有变化的值,这是为什么?
这是因为我们在声明str的时候限制了它的字符长度,使用 类型转换CAST('abc' AS CHAR(30))
就可以得到复制的字符串了。
**注意:**这里也可能会报错,看mysql模式在严格模式下这里会显示Error Code: 1406. Data too long for column ‘str’ at row 1
关于strict SQL mode和nonstrict SQL mode:mysql 严格模式 Strict Mode说明
WITH RECURSIVE cte AS
(SELECT 1 AS n, CAST('abc' AS CHAR(20)) AS strUNION ALLSELECT n + 1, CONCAT(str, str) FROM cte WHERE n < 3
)
SELECT * FROM cte;
+---+--------------+
| n | str |
+---+--------------+
| 1 | abc |
| 2 | abcabc |
| 3 | abcabcabcabc |
+---+--------------+
当然,如果上一行的值有多个,我们还可以对多个值进行重新组合得到我们想要的结果,比如下面这个例子。
例子3:生成斐波那契数列
WITH RECURSIVE fibonacci (n, fib_n, next_fib_n) AS
(SELECT 1, 0, 1UNION ALLSELECT n + 1, next_fib_n, fib_n + next_fib_nFROM fibonacci WHERE n < 92
)
SELECT * FROM fibonacci;
+----+---------------------+---------------------+
| n | fib_n | next_fib_n |
+----+---------------------+---------------------+
| 1 | 0 | 1 |
| 2 | 1 | 1 |
| 3 | 1 | 2 |
| 4 | 2 | 3 |
| 5 | 3 | 5 |
| 6 | 5 | 8 |
| 7 | 8 | 13 |
| 8 | 13 | 21 |
| 9 | 21 | 34 |
| 10 | 34 | 55 |
| 11 | 55 | 89 |
| 12 | 89 | 144 |
| 13 | 144 | 233 |
| 14 | 233 | 377 |
| 15 | 377 | 610 |
| 16 | 610 | 987 |
| 17 | 987 | 1597 |
| 18 | 1597 | 2584 |
| 19 | 2584 | 4181 |
| 20 | 4181 | 6765 |
| 21 | 6765 | 10946 |
| 22 | 10946 | 17711 |
| 23 | 17711 | 28657 |
| 24 | 28657 | 46368 |
| 25 | 46368 | 75025 |
| 26 | 75025 | 121393 |
| 27 | 121393 | 196418 |
| 28 | 196418 | 317811 |
| 29 | 317811 | 514229 |
| 30 | 514229 | 832040 |
| 31 | 832040 | 1346269 |
| 32 | 1346269 | 2178309 |
| 33 | 2178309 | 3524578 |
| 34 | 3524578 | 5702887 |
| 35 | 5702887 | 9227465 |
| 36 | 9227465 | 14930352 |
| 37 | 14930352 | 24157817 |
| 38 | 24157817 | 39088169 |
| 39 | 39088169 | 63245986 |
| 40 | 63245986 | 102334155 |
| 41 | 102334155 | 165580141 |
| 42 | 165580141 | 267914296 |
| 43 | 267914296 | 433494437 |
| 44 | 433494437 | 701408733 |
| 45 | 701408733 | 1134903170 |
| 46 | 1134903170 | 1836311903 |
| 47 | 1836311903 | 2971215073 |
| 48 | 2971215073 | 4807526976 |
| 49 | 4807526976 | 7778742049 |
| 50 | 7778742049 | 12586269025 |
| 51 | 12586269025 | 20365011074 |
| 52 | 20365011074 | 32951280099 |
| 53 | 32951280099 | 53316291173 |
| 54 | 53316291173 | 86267571272 |
| 55 | 86267571272 | 139583862445 |
| 56 | 139583862445 | 225851433717 |
| 57 | 225851433717 | 365435296162 |
| 58 | 365435296162 | 591286729879 |
| 59 | 591286729879 | 956722026041 |
| 60 | 956722026041 | 1548008755920 |
| 61 | 1548008755920 | 2504730781961 |
| 62 | 2504730781961 | 4052739537881 |
| 63 | 4052739537881 | 6557470319842 |
| 64 | 6557470319842 | 10610209857723 |
| 65 | 10610209857723 | 17167680177565 |
| 66 | 17167680177565 | 27777890035288 |
| 67 | 27777890035288 | 44945570212853 |
| 68 | 44945570212853 | 72723460248141 |
| 69 | 72723460248141 | 117669030460994 |
| 70 | 117669030460994 | 190392490709135 |
| 71 | 190392490709135 | 308061521170129 |
| 72 | 308061521170129 | 498454011879264 |
| 73 | 498454011879264 | 806515533049393 |
| 74 | 806515533049393 | 1304969544928657 |
| 75 | 1304969544928657 | 2111485077978050 |
| 76 | 2111485077978050 | 3416454622906707 |
| 77 | 3416454622906707 | 5527939700884757 |
| 78 | 5527939700884757 | 8944394323791464 |
| 79 | 8944394323791464 | 14472334024676221 |
| 80 | 14472334024676221 | 23416728348467685 |
| 81 | 23416728348467685 | 37889062373143906 |
| 82 | 37889062373143906 | 61305790721611591 |
| 83 | 61305790721611591 | 99194853094755497 |
| 84 | 99194853094755497 | 160500643816367088 |
| 85 | 160500643816367088 | 259695496911122585 |
| 86 | 259695496911122585 | 420196140727489673 |
| 87 | 420196140727489673 | 679891637638612258 |
| 88 | 679891637638612258 | 1100087778366101931 |
| 89 | 1100087778366101931 | 1779979416004714189 |
| 90 | 1779979416004714189 | 2880067194370816120 |
| 91 | 2880067194370816120 | 4660046610375530309 |
| 92 | 4660046610375530309 | 7540113804746346429 |
+----+---------------------+---------------------+
92 rows in set (0.06 sec)
试了下最多可以生成92位,93就报错BIGINT UNSIGNED value is out of range in ‘(fibonacci
.num
+ fibonacci
.next_num
)’,测试MySQL版本为8.0.21
改成这样:
WITH recursive fibonacci AS (SELECT 1 AS n,0 AS num,CAST(1 AS UNSIGNED) AS next_numUNION ALLSELECT n + 1, next_num, num + next_num FROM fibonacci WHERE n < 93
) SELECT * FROM fibonacci;
+----+---------------------+----------------------+
| n | num | next_num |
+----+---------------------+----------------------+
| 1 | 0 | 1 |
| 2 | 1 | 1 |
| 3 | 1 | 2 |
| 4 | 2 | 3 |
| 5 | 3 | 5 |
| 6 | 5 | 8 |
| 7 | 8 | 13 |
| 8 | 13 | 21 |
| 9 | 21 | 34 |
| 10 | 34 | 55 |
| 11 | 55 | 89 |
| 12 | 89 | 144 |
| 13 | 144 | 233 |
| 14 | 233 | 377 |
| 15 | 377 | 610 |
| 16 | 610 | 987 |
| 17 | 987 | 1597 |
| 18 | 1597 | 2584 |
| 19 | 2584 | 4181 |
| 20 | 4181 | 6765 |
| 21 | 6765 | 10946 |
| 22 | 10946 | 17711 |
| 23 | 17711 | 28657 |
| 24 | 28657 | 46368 |
| 25 | 46368 | 75025 |
| 26 | 75025 | 121393 |
| 27 | 121393 | 196418 |
| 28 | 196418 | 317811 |
| 29 | 317811 | 514229 |
| 30 | 514229 | 832040 |
| 31 | 832040 | 1346269 |
| 32 | 1346269 | 2178309 |
| 33 | 2178309 | 3524578 |
| 34 | 3524578 | 5702887 |
| 35 | 5702887 | 9227465 |
| 36 | 9227465 | 14930352 |
| 37 | 14930352 | 24157817 |
| 38 | 24157817 | 39088169 |
| 39 | 39088169 | 63245986 |
| 40 | 63245986 | 102334155 |
| 41 | 102334155 | 165580141 |
| 42 | 165580141 | 267914296 |
| 43 | 267914296 | 433494437 |
| 44 | 433494437 | 701408733 |
| 45 | 701408733 | 1134903170 |
| 46 | 1134903170 | 1836311903 |
| 47 | 1836311903 | 2971215073 |
| 48 | 2971215073 | 4807526976 |
| 49 | 4807526976 | 7778742049 |
| 50 | 7778742049 | 12586269025 |
| 51 | 12586269025 | 20365011074 |
| 52 | 20365011074 | 32951280099 |
| 53 | 32951280099 | 53316291173 |
| 54 | 53316291173 | 86267571272 |
| 55 | 86267571272 | 139583862445 |
| 56 | 139583862445 | 225851433717 |
| 57 | 225851433717 | 365435296162 |
| 58 | 365435296162 | 591286729879 |
| 59 | 591286729879 | 956722026041 |
| 60 | 956722026041 | 1548008755920 |
| 61 | 1548008755920 | 2504730781961 |
| 62 | 2504730781961 | 4052739537881 |
| 63 | 4052739537881 | 6557470319842 |
| 64 | 6557470319842 | 10610209857723 |
| 65 | 10610209857723 | 17167680177565 |
| 66 | 17167680177565 | 27777890035288 |
| 67 | 27777890035288 | 44945570212853 |
| 68 | 44945570212853 | 72723460248141 |
| 69 | 72723460248141 | 117669030460994 |
| 70 | 117669030460994 | 190392490709135 |
| 71 | 190392490709135 | 308061521170129 |
| 72 | 308061521170129 | 498454011879264 |
| 73 | 498454011879264 | 806515533049393 |
| 74 | 806515533049393 | 1304969544928657 |
| 75 | 1304969544928657 | 2111485077978050 |
| 76 | 2111485077978050 | 3416454622906707 |
| 77 | 3416454622906707 | 5527939700884757 |
| 78 | 5527939700884757 | 8944394323791464 |
| 79 | 8944394323791464 | 14472334024676221 |
| 80 | 14472334024676221 | 23416728348467685 |
| 81 | 23416728348467685 | 37889062373143906 |
| 82 | 37889062373143906 | 61305790721611591 |
| 83 | 61305790721611591 | 99194853094755497 |
| 84 | 99194853094755497 | 160500643816367088 |
| 85 | 160500643816367088 | 259695496911122585 |
| 86 | 259695496911122585 | 420196140727489673 |
| 87 | 420196140727489673 | 679891637638612258 |
| 88 | 679891637638612258 | 1100087778366101931 |
| 89 | 1100087778366101931 | 1779979416004714189 |
| 90 | 1779979416004714189 | 2880067194370816120 |
| 91 | 2880067194370816120 | 4660046610375530309 |
| 92 | 4660046610375530309 | 7540113804746346429 |
| 93 | 7540113804746346429 | 12200160415121876738 |
+----+---------------------+----------------------+
93 rows in set (0.10 sec)
可以生成到93个(长度20了),但是94+都不行了,达到了bigint上限
语法说明:
UNION ALL
与UNION DISTINCT
UNION ALL:非递归部分和递归部分用UNION ALL分隔,那么所有的行都会被加入到最后的表中
UNION DISTINCT:非递归部分和递归部分用UNION DISTINCT分隔,重复的行被消除。这对于执行传递闭包的查询非常有用,以避免无限循环。
limit控制递归次数
recursive(第二个select)不能使用的结构:
官网的描述:
The recursive SELECT part must not contain these constructs:(递归查询部分必须不含下列结构)
Aggregate functions such as SUM(),聚合函数例如SUM()
Window functions
GROUP BY
ORDER BY
DISTINCT
限制递归次数/时间:
当出现不符合设置情况的会报错,分为以下几种设置方法:
cte_max_recursion_depth :default 设置为1000,表达递归的层数.可以使用如下语句修改这个值:
SET SESSION cte_max_recursion_depth = 10; -- permit only shallow recursion
SET SESSION cte_max_recursion_depth = 1000000; -- permit deeper recursion
当然也可以设置为global,也就是set global cte_max_recursion_depth = 1000000;这样子就对全局的递归都有限制
max_execution_time :设置最近的递归时间
SET max_execution_time = 1000; -- impose one second timeout
MAX_EXECUTION_TIME:设置全局的递归时间
官网文档说明如下:
The cte_max_recursion_depth system variable enforces a limit on the
number of recursion levels for CTEs. The server terminates execution
of any CTE that recurses more levels than the value of this variable.
The max_execution_time system variable enforces an execution timeout
for SELECT statements executed within the current session.
The MAX_EXECUTION_TIME optimizer hint enforces a per-query execution
timeout for the SELECT statement in which it appears.
limit:限之最大行的数量
WITH RECURSIVE cte (n) AS
(SELECT 1UNION ALLSELECT n + 1 FROM cte LIMIT 10000
)
SELECT * FROM cte;
报错Recursive query aborted after 1001 iterations. Try increasing @@cte_max_recursion_depth to a larger value.
MySql 实现递归with recursive相关推荐
- 递归神经网络(Recursive Neural Network, RNN)
信息往往还存在着诸如树结构.图结构等更复杂的结构.这就需要用到递归神经网络 (Recursive Neural Network, RNN),巧合的是递归神经网络的缩写和循环神经网络一样,也是RNN,递 ...
- RLS递归最小二乘法(Recursive Least Squares)
RLS递归最小二乘法(Recursive Least Squares) 感谢B站Up 凩子白的讲解视频, 大多数的RLS算法介绍都是从各种专业领域角度讲解的(比如滤波器等角度), 对于缺乏专业背景的同 ...
- 深度学习——结构递归神经网络(Recursive NN)
深度学习--结构递归神经网络(Recursive NN) 1.递归神经网络介绍 目前,递归神经网络一共包含两种,一种是时间递归神经网络(Recurrent NN),另外一种是结构性递归神经网络(Rec ...
- mysql之递归树查询
mysql之递归树查询 写在前面 最近一段时间做的产品使用到了mysql数据库,虽然之前也使用过,但都是在业余时间使用,真正在项目中使用还是发现mysql的一些不同之处,比如函数.存储过程等, ...
- mysql+mybatis递归调用
递归调用的应用场景常常出现在多级嵌套的情况,比如树形的菜单.下面通过一个简单的例子来实现mysql+mybatis的递归. 数据模型 private Integer categoryId;privat ...
- mysql cte递归_CTE 递归查询全解
TSQL脚本能实现递归查询,用户使用共用表表达式 CTE(Common Table Expression),只需要编写少量的代码,就能实现递归查询.本文详细介绍CTE递归调用的特性和使用示例,递归查询 ...
- 有趣的递归缩写(Recursive acronym)
看到一些递归缩写,很想知道到底有多少缩写是这样的,于是Google了一下,知道了英文说法是Recursive acronym,从 Wikipedia上摘录了一些: 递归缩写是一种在全称中递归引用它自身 ...
- 递归数列(recursive sequence)
递归数列-递归数列 (recursive sequence ):一种用归纳方法给定的数列. 递归数列-举例 例如,等比数列可以用归纳方法来定义,先定义第一项 a1 的值( a1 ≠ 0 ),对 于以后 ...
- Oracle转换MySql之递归start with
Oracle转换Mysql之start with: oracle转mysql其实很多细节,这边就不一 一 描述了,这边先整理些"坎"吧! Oracle中start with - : ...
最新文章
- My blog please navigate to http://hi.baidu.com/248828412
- linux自己带的apache重新启动
- linux alpine 用dockerfile创建的ssh镜像
- Android群英传笔记——第四章:ListView使用技巧
- java 可用内存_总可用内存java
- 【数据结构与算法-2】链表
- springboot web 服务器选择
- python matplotlib画图产生的Type 3 fonts字体没有嵌入问题
- rxjs的pipe和map配合使用的单步调试
- SSH连接linux时,长时间不操作就断开的解决方案
- python class def 格式_Python symbol.classdef方法代码示例
- windows下安装Redis数据库
- 如何使用XGBoost开发随机森林集成
- 03.subview_and_superview
- Brocade 6510 交换机清空配置,重新initiator交换机
- VC所有版本一键清除缓存垃圾脚本
- oracle12c 删除磁盘组,12C RAC重装无法识别磁盘组(AFD新特性)
- AFM成像表面形貌和表面粗糙度
- HDFS Router-based Federation
- 神经网络解决推荐系统问题(NCF)