MySQL8.0的WITH查询详情


Posted in MySQL onAugust 30, 2021

 关于MySQL8的WITH查询学习

前言:

对于逻辑复杂的sql,with可以大大减少临时表的数量,提升代码的可读性、可维护性
MySQL 8.0终于开始支持with语句了,对于复杂查询,可以不用写那么多的临时表了。
可以查看官方文档【点击跳转】

1、示例

官方第一个示例,可以看出该查询语句创建了cte1,cte2,cte3,cte4这4个临时表,后面的临时表依赖前面的临时表数据。
最后一行为最终查询结果,实际ct4因为ct3结果包含3行数据,但是使用MAX,MIN得到一行结果。

WITH cte1(txt) AS (SELECT "This "),
     cte2(txt) AS (SELECT CONCAT(cte1.txt,"is a ") FROM cte1),
     cte3(txt) AS (SELECT "nice query" UNION
                   SELECT "query that rocks" UNION
                   SELECT "query"),
     cte4(txt) AS (SELECT concat(cte2.txt, cte3.txt) FROM cte2, cte3)
SELECT MAX(txt), MIN(txt) FROM cte4;
 
+----------------------------+----------------------+
| MAX(txt)                   | MIN(txt)             |
+----------------------------+----------------------+
| This is a query that rocks | This is a nice query |
+----------------------------+----------------------+
1 row in set (0,00 sec)

官方第二个示例是递归的用法,根据阅读文档,我分析下面查询结果如下。
首先定义一个临时表my_cte
分析SELECT 1 AS n,这个是决定临时表的列名为n,值为1
然后SELECT 1+n FROM my_cte WHERE n<10,这个是递归查询n<10,并将1+n作为结果填充临时表
最终使用SELECT * FROM my_cte,查询临时表,因此查询出的结果就显而易见了

WITH RECURSIVE my_cte AS
(
  SELECT 1 AS n
  UNION ALL
  SELECT 1+n FROM my_cte WHERE n<10
)
SELECT * FROM my_cte;
 
+------+
| n    |
+------+
|    1 |
|    2 |
|    3 |
|    4 |
|    5 |
|    6 |
|    7 |
|    8 |
|    9 |
|   10 |
+------+
10 rows in set (0,00 sec)

根据我的理解写了如下2个不一样的查询,查询结果都一样。
值得注意的是临时表里面的多个查询列数量和类型必须一样,不然会报错。

这个是将临时表列名指定在第一行
WITH RECURSIVE my_cte(a,b,c) AS
(
  SELECT 1,1,1
  UNION ALL
  SELECT 1+a,2+b,3+c FROM my_cte WHERE a<10
)
SELECT * FROM my_cte;
 
这个第一行没有指定列名,然后列名由第一个查询返回结果确定
WITH RECURSIVE my_cte AS
(
  SELECT 1 AS a,1 AS b,1 AS c
  UNION ALL
  SELECT 1+a,2+b,3+c FROM my_cte WHERE a<10
)
SELECT * FROM my_cte;

根据官方文档,临时表的语法模板如下,是可以有很多行的查询共同组成。

WITH RECURSIVE cte_name [list of column names ] AS
(
  SELECT ...      <-- specifies initial set
  UNION ALL
  SELECT ...      <-- specifies initial set
  UNION ALL
  ...
  SELECT ...      <-- specifies how to derive new rows
  UNION ALL
  SELECT ...      <-- specifies how to derive new rows
  ...
)
[, any number of other CTE definitions ]

官方文档还列出了,使用临时表时可以增删改查新表,具体可以去阅读官方文档。

3、练习

关于递归的练习主要用于表里面包含父节点id之类的,详情可以参考下面的练习。
定义下面这样的表,存储每个区域(省、市、区)的id,名字及上级区域的pid

CREATE TABLE tb(id VARCHAR(3), pid VARCHAR(3), name VARCHAR(64));
 
INSERT INTO tb VALUES('002', 0, '浙江省');
INSERT INTO tb VALUES('001', 0, '广东省');
INSERT INTO tb VALUES('003', '002', '衢州市');
INSERT INTO tb VALUES('004', '002', '杭州市');
INSERT INTO tb VALUES('005', '002', '湖州市');
INSERT INTO tb VALUES('006', '002', '嘉兴市');
INSERT INTO tb VALUES('007', '002', '宁波市');
INSERT INTO tb VALUES('008', '002', '绍兴市');
INSERT INTO tb VALUES('009', '002', '台州市');
INSERT INTO tb VALUES('010', '002', '温州市');
INSERT INTO tb VALUES('011', '002', '丽水市');
INSERT INTO tb VALUES('012', '002', '金华市');
INSERT INTO tb VALUES('013', '002', '舟山市');
INSERT INTO tb VALUES('014', '004', '上城区');
INSERT INTO tb VALUES('015', '004', '下城区');
INSERT INTO tb VALUES('016', '004', '拱墅区');
INSERT INTO tb VALUES('017', '004', '余杭区');
INSERT INTO tb VALUES('018', '011', '金东区');
INSERT INTO tb VALUES('019', '001', '广州市');
INSERT INTO tb VALUES('020', '001', '深圳市');
 
WITH RECURSIVE cte AS (
 SELECT id,name FROM tb WHERE id='002'
 UNION ALL
 SELECT k.id, CONCAT(c.name,'->',k.name) AS name FROM tb k INNER JOIN cte c ON c.id = k.pid
) SELECT * FROM cte;

执行结果:

MySQL8.0的WITH查询详情

分析结果包含第一行SELECT id,name FROM tb WHERE id='002'的数据,此时表中只有一行数据
然后连表查询SELECT k.id, CONCAT(c.name,'->',k.name) AS name FROM tb k INNER JOIN cte c ON c.id = k.pid,递归的将父节点数据放入临时表
最终查询出来的就是递归的结果。

到此这篇关于MySQL的WITH查询详情的文章就介绍到这了,更多相关MySQL的WITH查询内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

MySQL 相关文章推荐
简单了解 MySQL 中相关的锁
May 25 MySQL
MYSQL主从数据库同步备份配置的方法
May 26 MySQL
Mysql systemctl start mysqld报错的问题解决
Jun 03 MySQL
MySQL 十大常用字符串函数详解
Jun 30 MySQL
MySQL数据库中varchar类型的数字比较大小的方法
Nov 17 MySQL
进阶篇之linux环境下安装MySQL数据库
Apr 09 MySQL
MySQL分区以及建索引的方法总结
Apr 13 MySQL
MySQL 语句执行顺序举例解析
Jun 05 MySQL
mysql实现将字符串字段转为数字排序或比大小
Jun 14 MySQL
MySQL的表级锁,行级锁,排它锁和共享锁
Jul 15 MySQL
SQLServer常见数学函数梳理总结
Aug 05 MySQL
MySQL 原理与优化之Update 优化
Aug 14 MySQL
Prometheus 监控MySQL使用grafana展示
Aug 30 #MySQL
MySQL命令无法输入中文问题的解决方式
Aug 30 #MySQL
mysql 索引合并的使用
Aug 30 #MySQL
MySQL去除重叠时间求时间差和的实现
Aug 23 #MySQL
Mysql数据库中datetime、bigint、timestamp来表示时间选择,谁来存储时间效率最高
Aug 23 #MySQL
MySQL的全局锁和表级锁的具体使用
Aug 23 #MySQL
MySQL令人大跌眼镜的隐式转换
Aug 23 #MySQL
You might like
无JS,完全php面向过程数据分页实现代码
2012/08/27 PHP
php禁止直接从浏览器输入地址访问.php文件的方法
2014/11/04 PHP
php使用curl详细解析及问题汇总
2016/08/11 PHP
ThinkPHP 5.1 跨域配置方法
2019/10/11 PHP
jquery中ajax函数执行顺序问题之如何设置同步
2014/02/28 Javascript
JavaScript获取鼠标移动时的坐标(兼容IE8、chome谷歌、Firefox)
2014/09/13 Javascript
js实现在同一窗口浏览图片
2014/09/17 Javascript
Nodejs实现的一个简单udp广播服务器、客户端
2014/09/25 NodeJs
Node.js开发之访问Redis数据库教程
2015/01/14 Javascript
javascript中setTimeout使用指南
2015/07/26 Javascript
js实现网页多级级联菜单代码
2015/08/20 Javascript
基于JavaScript实现熔岩灯效果导航菜单
2017/01/04 Javascript
快速掌握jQuery插件开发
2017/01/19 Javascript
JavaScript轮播图简单制作方法
2017/02/20 Javascript
Vue和Bootstrap的整合思路详解
2017/06/30 Javascript
无限循环轮播图之运动框架(原生JS实现)
2017/10/01 Javascript
JavaScript使用math.js进行精确计算操作示例
2018/06/19 Javascript
python3生成随机数实例
2014/10/20 Python
python实现判断数组是否包含指定元素的方法
2015/07/15 Python
Python中pip更新和三方插件安装说明
2018/07/08 Python
Python 十六进制整数与ASCii编码字符串相互转换方法
2018/07/09 Python
更新pip3与pyttsx3文字语音转换的实现方法
2019/08/08 Python
Django 实现Admin自动填充当前用户的示例代码
2019/11/18 Python
通过 Python 和 OpenCV 实现目标数量监控
2020/01/05 Python
Python HTMLTestRunner可视化报告实现过程解析
2020/04/10 Python
python3读取autocad图形文件.py实例
2020/06/05 Python
keras多显卡训练方式
2020/06/10 Python
澳洲的UGG雪地靴超级市场:Uggs.com.au
2020/04/06 全球购物
解除财产保全担保书
2014/05/20 职场文书
大学生就业协议书范本(适用于公司企业)
2014/10/07 职场文书
关于环保的宣传稿
2015/07/23 职场文书
安全生产隐患排查制度
2015/08/05 职场文书
五年级作文之劳动作文
2019/11/12 职场文书
零基础学java之带参数以及返回值的方法
2022/04/10 Java/Android
V Rising 服务器搭建图文教程
2022/06/16 Servers
SpringCloud中分析讲解Feign组件添加请求头有哪些坑梳理
2022/06/21 Java/Android