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 08 MySQL
mysql死锁和分库分表问题详解
Apr 16 MySQL
MySql学习笔记之事务隔离级别详解
May 12 MySQL
为什么MySQL选择Repeatable Read作为默认隔离级别
Jul 26 MySQL
Mysql实现简易版搜索引擎的示例代码
Aug 30 MySQL
mysql事务隔离级别详情
Oct 24 MySQL
MySQL数据库查询进阶之多表查询详解
Apr 08 MySQL
Mysql 如何合理地统计一个数据库里的所有表的数据量
Apr 18 MySQL
Mysql InnoDB 的内存逻辑架构
May 06 MySQL
MYSQL事务的隔离级别与MVCC
May 25 MySQL
mysql字段为NULL索引是否会失效实例详解
May 30 MySQL
postgresql如何找到表中重复数据的行并删除
May 08 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采用自定义函数实现遍历目录下所有文件的方法
2014/08/19 PHP
php打印一个边长为N的实心和空心菱型的方法
2015/03/02 PHP
PHP使用array_fill定义多维数组的方法
2015/03/18 PHP
php获取POST数据的三种方法实例详解
2016/12/20 PHP
js 函数调用模式小结
2011/12/26 Javascript
Jquery ajaxStart()与ajaxStop()方法(实例讲解)
2013/12/18 Javascript
深入理解JavaScript系列(37):设计模式之享元模式详解
2015/03/04 Javascript
学习JavaScript事件流和事件处理程序
2016/01/25 Javascript
webpack使用 babel-loader 转换 ES6代码示例
2017/08/21 Javascript
解决Vue编译时写在style中的路径问题
2017/09/21 Javascript
详解cordova打包成webapp的方法
2017/10/18 Javascript
jQuery表单元素过滤选择器用法实例分析
2019/02/20 jQuery
JS开发常用工具函数(小结)
2019/07/04 Javascript
微信小程序自定义头部导航栏(组件化)
2019/11/15 Javascript
vue-cli —— 如何局部修改Element样式
2020/10/22 Javascript
uniapp微信小程序实现一个页面多个倒计时
2020/11/01 Javascript
[03:10]超级美酒第四天 fy拉比克秀 大合集
2018/06/05 DOTA
简介Python设计模式中的代理模式与模板方法模式编程
2016/02/02 Python
把JSON数据格式转换为Python的类对象方法详解(两种方法)
2019/06/04 Python
Python Matplotlib 基于networkx画关系网络图
2019/07/10 Python
django用户登录验证的完整示例代码
2019/07/21 Python
解决pytorch-yolov3 train 报错的问题
2020/02/18 Python
python 使用raw socket进行TCP SYN扫描实例
2020/05/05 Python
澳大利亚波西米亚风情网上商店:Czarina
2019/03/18 全球购物
Theo + George官方网站:都柏林时尚品牌
2019/04/08 全球购物
任课老师推荐信范文
2013/11/24 职场文书
社区服务活动总结
2014/05/07 职场文书
不错的求职信范文
2014/07/20 职场文书
2014银行授权委托书样本
2014/10/04 职场文书
介绍信怎么写
2015/05/05 职场文书
消费者投诉书范文
2015/07/02 职场文书
《多彩的民间艺术》教学反思
2016/02/16 职场文书
创业计划书之烤红薯
2019/09/26 职场文书
如何搭建 MySQL 高可用高性能集群
2021/06/21 MySQL
MySQL库表太大怎么办? 数据库分库分表项目实践
2022/04/11 MySQL
三星 3nm 芯片将于第二季度开始量产
2022/04/29 数码科技