当前位置:网站首页>mysql 递归函数with recursive的用法
mysql 递归函数with recursive的用法
2022-07-30 20:14:00 【良月生秋】
AS 用法:
AS在mysql用来给列/表起别名.
有时,列的名称是一些表达式,使查询的输出很难理解。要给列一个描述性名称,可以使用列别名。
要给列添加别名,可以使用AS关键词后跟别名
例子1:
SELECT
[column_1 | expression] AS col_name
FROM table_name;
如果别名包含空格,则必须引用以下内容:
例子2:
SELECT
[column_1 | expression] AS 'col name'
FROM table_name;
with(Common Table Expressions/CTE)用法:
with在mysql中被称为公共表达式,可以作为一个临时表然后在其他结构中调用.如果是自身调用那么就是后面讲的递归.
语法:
with_clause:
WITH [RECURSIVE]
cte_name [(col_name [, col_name] ...)] AS (subquery)
[, cte_name [(col_name [, col_name] ...)] AS (subquery)] ...
cte_name :公共表达式的名称,可以理解为表名,用来表示as后面跟着的子查询
col_name :公共表达式包含的列名,可以写也可以不写
例子1:
WITH
cte1 AS (SELECT a, b FROM table1),
cte2 AS (SELECT c, d FROM table2)
SELECT b, d FROM cte1 JOIN cte2
WHERE cte1.a = cte2.c;
例子2:
WITH cte (col1, col2) AS
(
SELECT 1, 2
UNION ALL
SELECT 3, 4
)
SELECT col1, col2 FROM cte;
例子3:
这里的第一个as后面接的是子查询,第二个as表示列名,而不是子查询.
WITH cte AS
(
SELECT 1 AS col1, 2 AS col2
UNION ALL
SELECT 3, 4
)
SELECT col1, col2 FROM cte;
with的合法用法:
在子查询(包括派生的表子查询)的开始处
SELECT … WHERE id IN (WITH … SELECT …) …
SELECT * FROM (WITH … SELECT …) AS dt …同一级别只允许一个WITH子句。同一级别的WITH后面跟着WITH是不允许的,下面是非法用法:
WITH cte1 AS (…) WITH cte2 AS (…) SELECT …
改为合法用法:
WITH cte1 AS (SELECT 1)
SELECT * FROM (WITH cte2 AS (SELECT 2) SELECT * FROM cte2 JOIN cte1) AS dt;
在这里面as代表列名,sql不是顺序执行的,这一点了解的话就很好理解这个as了
简单递归用法:
首先我们引出一个问题: 什么叫做递归
递归:给定函数初始条件,然后反复调用自身直到终止条件.
例子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.
用python实现就是:
def cte(n):
print(n)
if n<5:
cte(n+1)
也就是说,一个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 |
+------+------+
这里的话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 < 10
)
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 |
+------+-------+------------+
语法说明:
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() 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;
先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦
边栏推荐
- Mysql——字符串函数
- 时间复杂度与空间复杂度
- idea plugins搜索不到插件
- [PM only] Quickly count who else in the team has not registered and reported information, and quickly screen out the members of their own project team who have not completed the list of XXX work items
- After MySQL grouping, take the largest piece of data [optimal solution]
- 并发与并行的区别
- vlookup函数匹配不出来只显示公式的解决方法
- Install MySQL tutorial under Linux
- halcon——轮廓线
- How to copy table structure and table data in MySQL
猜你喜欢
360杜跃进:太空安全风险加剧,需打造一体化防御体系
Recommended system: cold start problem [user cold start, item cold start, system cold start]
移动web开发01
MySQL的Replace用法详解
【PM专用】快速统计团队还有谁没有登记上报信息,快速筛选出属于自己项目组的成员,未完成XXX工作事项的名单
MySql密码
MySQL database --- Addition, deletion, modification and query of MySQL tables (advanced)
Database indexes: indexes are not a panacea
基于人脸的常见表情识别(2)——数据获取与整理
化二次型为标准型
随机推荐
从离线到实时对客,湖仓一体释放全量数据价值
【请教】SQL语句按列1去重来计算列2之和?
18.客户端会话技术Cookie
银行数据资产转换能力弱?思迈特软件助力解决银行困境
vookloop函数怎么用?vlookup函数的使用方法介绍
倾斜文档扫描与字符识别(opencv,坐标变换分析)
To the operation of the int variable assignment is atom?
ERROR 1045 (28000) Access denied for user ‘root‘@‘localhost‘解决方法
OSS简单上传图片
Day31 LeetCode
Scala类中的属性
啊?现在初级测试招聘都要求会自动化了?
Install MySQL tutorial under Linux
MySQL database --- Addition, deletion, modification and query of MySQL tables (advanced)
365天挑战LeetCode1000题——Day 044 按公因数计算最大组件大小 并查集
湖仓一体电商项目(四):项目数据种类与采集
Apple Silicon配置二进制环境(一)
Interviewer Ali: Describe to me the phenomenon of cache breakdown, and talk about your solution?
MySQL kills 10 questions, how many questions can you stick to?
Cesium loads offline maps and offline terrain