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基础之常见函数
Apr 22 MySQL
MySQL为id选择合适的数据类型
Jun 07 MySQL
分析mysql中一条SQL查询语句是如何执行的
Jun 21 MySQL
QT连接MYSQL数据库的详细步骤
Jul 07 MySQL
MySQL数据库⾼可⽤HA实现小结
Jan 22 MySQL
Mysql Innodb存储引擎之索引与算法
Feb 15 MySQL
浅谈如何保证Mysql主从一致
Mar 13 MySQL
MySQL学习必备条件查询数据
Mar 25 MySQL
Nebula Graph解决风控业务实践
Mar 31 MySQL
navicat 连接Ubuntu虚拟机的mysql的操作方法
Apr 02 MySQL
Mysql查询时间区间日期列表,不会由于数据表数据影响
Apr 19 MySQL
MySql统计函数COUNT的具体使用详解
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
php去掉URL网址中带有PHPSESSID的配置方法
2014/07/08 PHP
PHP常见的序列化与反序列化操作实例分析
2019/10/28 PHP
PHP使用gearman进行异步的邮件或短信发送操作详解
2020/02/27 PHP
(转载)JavaScript中匿名函数,函数直接量和闭包
2007/05/08 Javascript
JavaScript中常见陷阱小结
2010/04/27 Javascript
javascript 学习笔记(六)浏览器类型及版本信息检测代码
2011/04/08 Javascript
js两行代码按指定格式输出日期时间
2011/10/21 Javascript
jQuery lazyLoad图片延迟加载插件的优化改造方法分享
2013/08/13 Javascript
JS完整获取IE浏览器信息包括类型、版本、语言等等
2014/05/22 Javascript
浅谈javascript获取元素transform参数
2015/07/24 Javascript
用v-html解决Vue.js渲染中html标签不被解析的问题
2016/12/14 Javascript
JavaScript实现定时页面跳转功能示例
2017/02/14 Javascript
js模拟支付宝密码输入框
2017/04/11 Javascript
easyui combogrid实现本地模糊搜索过滤多列
2017/05/13 Javascript
jquery.picsign图片标注组件实例详解
2018/02/02 jQuery
[43:32]2014 DOTA2华西杯精英邀请赛 5 25 LGD VS NewBee第一场
2014/05/26 DOTA
[54:29]2018DOTA2亚洲邀请赛 4.7 淘汰赛 VP vs LGD 第二场
2018/04/09 DOTA
[51:30]OG vs LGD 2018国际邀请赛淘汰赛BO3 第二场 8.26
2018/08/30 DOTA
python 回调函数和回调方法的实现分析
2016/03/23 Python
Python的标准模块包json详解
2017/03/13 Python
Python3中简单的文件操作及两个简单小实例分享
2017/06/18 Python
python搭建服务器实现两个Android客户端间收发消息
2018/04/12 Python
Python基于whois模块简单识别网站域名及所有者的方法
2018/04/23 Python
如何用Python制作微信好友个性签名词云图
2019/06/28 Python
Python实现搜索算法的实例代码
2020/01/02 Python
Pytorch释放显存占用方式
2020/01/13 Python
使用python图形模块turtle库绘制樱花、玫瑰、圣诞树代码实例
2020/03/16 Python
python实现文法左递归的消除方法
2020/05/22 Python
Python3通过chmod修改目录或文件权限的方法示例
2020/06/08 Python
香港草莓网:Strawberrynet香港
2019/05/10 全球购物
简述synchronized和java.util.concurrent.locks.Lock的异同
2014/12/08 面试题
和睦家庭事迹
2014/05/14 职场文书
煤矿开采专业求职信
2014/07/08 职场文书
幼儿园重阳节活动总结
2015/05/05 职场文书
花木兰观后感
2015/06/10 职场文书
JS监听Esc 键触发事键
2021/04/14 Javascript