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 相关文章推荐
MySQL8.0.24版本Release Note的一些改进点
Apr 22 MySQL
详解MySQL连接挂死的原因
May 18 MySQL
安装配置mysql及Navicat prenium的详细流程
Jun 10 MySQL
解决mysql问题:由于找不到MSVCR120.dll,无法继续执行代码
Jun 26 MySQL
浅谈MySQL表空间回收的正确姿势
Oct 05 MySQL
MySQL8.0升级的踩坑历险记
Nov 01 MySQL
MySQL面试题讲解之如何设置Hash索引
Nov 01 MySQL
MySQL和Oracle批量插入SQL的通用写法示例
Nov 17 MySQL
Linux7.6二进制安装Mysql8.0.27详细操作步骤
Nov 27 MySQL
MySQL Server层四个日志的实现
Mar 31 MySQL
MySQL提取JSON字段数据实现查询
Apr 22 MySQL
MySQL中dd::columns表结构转table过程及应用详解
Sep 23 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将数据库中的电话号码读取出来并生成图片
2008/08/31 PHP
php 静态化实现代码
2009/03/20 PHP
PHP文件上传原理简单分析
2011/05/29 PHP
浅析PHP中的字符串编码转换(自动识别原编码)
2013/07/02 PHP
thinkphp3查询mssql数据库乱码解决方法分享
2014/02/11 PHP
ThinkPHP学习笔记(一)ThinkPHP部署
2014/06/22 PHP
javascript 读取XML数据,在页面中展现、编辑、保存的实现
2009/10/27 Javascript
JS图片浏览组件PhotoLook的公开属性方法介绍和进阶实例代码
2010/11/09 Javascript
js性能优化 如何更快速加载你的JavaScript页面
2012/03/17 Javascript
js为鼠标添加右击事件防止默认的右击菜单弹出
2013/07/29 Javascript
jQuery获取当前点击的对象元素(实现代码)
2016/05/19 Javascript
JS选取DOM元素的简单方法
2016/07/08 Javascript
jQuery Easy UI中根据第一个下拉框选中的值设置第二个下拉框是否可以编辑
2016/11/29 Javascript
select下拉框插件jquery.editable-select详解
2017/01/22 Javascript
nodejs使用express创建一个简单web应用
2017/03/31 NodeJs
详解JavaScript作用域 闭包
2020/07/29 Javascript
下载安装setuptool和pip linux安装pip    
2014/01/24 Python
python基础入门学习笔记(Python环境搭建)
2016/01/13 Python
pandas修改DataFrame列名的实现方法
2019/02/22 Python
python爬虫 execjs安装配置及使用
2019/07/30 Python
Tensorflow中的dropout的使用方法
2020/03/13 Python
浅谈keras中的目标函数和优化函数MSE用法
2020/06/10 Python
css3如何绘制一个圆圆的loading转圈动画
2018/01/09 HTML / CSS
html5视频媒体标签video的使用方法及完整参数说明详解
2019/09/27 HTML / CSS
尼克松手表官网:Nixon手表
2019/03/17 全球购物
信号量和自旋锁的区别?如何选择使用?
2015/09/08 面试题
外企财务年会演讲稿
2014/01/03 职场文书
银行营业厅大堂经理岗位职责
2014/01/06 职场文书
2014年入党积极分子党课学习心得体会模板
2014/04/03 职场文书
宪法宣传周工作方案
2014/05/26 职场文书
幼儿教师师德师风自我剖析材料
2014/09/29 职场文书
2014年精神文明工作总结
2014/12/23 职场文书
学校2016年九九重阳节活动总结
2016/04/01 职场文书
创业计划书之面包店
2019/09/12 职场文书
mysql脏页是什么
2021/07/26 MySQL
英国数字版游戏销量周榜公布 《小缇娜的奇幻之地》登顶
2022/04/03 其他游戏