MySql 实现递归with recursive

MySQL版本8.0.21-2

递归方式生成一个临时表tmp,且填充了10条数据

WITH recursive tmp ( a, b ) AS (
	SELECT
		1,
		'2022-01-01' UNION ALL
	SELECT
		ROUND( RAND()* 10 ),
		b - INTERVAL ROUND( RAND() * 1000 ) DAY 
	FROM
		TMP 
	LIMIT 10 
	) TABLE tmp;

MySql 实现递归with recursive_第1张图片

以列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;

MySql 实现递归with recursive_第2张图片

输出1~n:

WITH RECURSIVE cte (n) AS
(
  SELECT 1
  UNION ALL
  SELECT 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
* 
FROM
	cte;
#或者
WITH RECURSIVE cte AS (
	SELECT
		1 AS n,
		1 AS m UNION ALL
	SELECT
		n + 1,
		( n + 1 ) * m 
	FROM
		cte 
	WHERE
		n < 10 
	) SELECT
	* 
FROM
	cte;
+----+---------+
| 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
* 
FROM
	cte;
+----+-----+
| 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 1
  UNION ALL
  SELECT 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 str
  UNION ALL
  SELECT 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 str
  UNION ALL
  SELECT 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, 1
  UNION ALL
  SELECT n + 1, next_fib_n, fib_n + next_fib_n
    FROM 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_num
	UNION ALL
	SELECT 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 ALLUNION 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 1
  UNION ALL
  SELECT 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,mysql,sql,数据库)