【MySQL】MySQL 8.0 新特性之 - 公用表表达式(CTE)
MySQL 8.0 新特性之 - 公用表表达式(CTE)
- 1. 公用表表达式(CTE) - WITH 介绍
- 1.1 公用表表表达式
- 1.1.1 什么是公用表表达式
- 1.1.2 CTE 语法
- 1.1.3 CTE示例
- 1.3 递归 CTE
- 1.3.1 递归 CTE 简介
- 1.3.2 递归成员限制
- 1.3.3 递归 CTE 示例
- 1.3.4 使用递归 CTE 遍历分层数据
- 2. CTE 与 Derived Table
- 在 5.6 版本中
- 在 5.7 版本中
- 在 8.0 版本中
1. 公用表表达式(CTE) - WITH 介绍
1.1 公用表表表达式
1.1.1 什么是公用表表达式
官网:https://dev.mysql.com/doc/refman/8.0/en/with.html#common-table-expressions
MySQL 从 8.0 开始支持 WITH 语法,即:Common Table Expressions - CTE,共用表表达式。
CTE 是一个命名的临时结果集合,仅在单个 SQL 语句(select、insert、update 或 delete)的执行范围内存在。
与派生表
类似的是:CTE 不作为对象存储,仅在查询执行期间持续。与派生表
不同的是:CTE 可以是自引用(递归CTE),也可以在同一查询中多次引用。此外,与派生表相比,CTE 提供了更好的可读性和性能。
1.1.2 CTE 语法
CTE 的结构包括:名称、可选列列表和定义 CTE 的查询。定义 CTE 后,可以像 select、insert、update、delete 或 create view
语句中的视图一样使用它。
with cte_name (column_list) as (query)
select * from cte_name;
查询中的列数必须与 column_list 中的列数相同。 如果省略 column_list,CTE 将使用定义 CTE 的查询的列列表。
1.1.3 CTE示例
初始化数据:
-- create table
create table department
(id bigint auto_increment comment '主键ID'primary key,dept_name varchar(32) not null comment '部门名称',parent_id bigint default 0 not null comment '父级id'
);-- insert values
insert into `department` values (null, '总部', 0);
insert into `department` values (null, '研发部', 1);
insert into `department` values (null, '测试部', 1);
insert into `department` values (null, '产品部', 1);
insert into `department` values (null, 'Java组', 2);
insert into `department` values (null, 'Python组', 2);
insert into `department` values (null, '前端组', 2);
insert into `department` values (null, '供应链测试组', 3);
insert into `department` values (null, '商城测试组', 3);
insert into `department` values (null, '供应链产品组', 4);
insert into `department` values (null, '商城产品组', 4);
insert into `department` values (null, 'Java1组', 5);
insert into `department` values (null, 'Java2组', 5);
(1)最基本的CTE语法:
mysql> with cte1 as (select * from `department` where id in (1, 2)),-> cte2 as (select * from `department` where id in (2, 3))-> select *-> from cte1-> join cte2-> where cte1.id = cte2.id;
+----+-----------+-----------+----+-----------+-----------+
| id | dept_name | parent_id | id | dept_name | parent_id |
+----+-----------+-----------+----+-----------+-----------+
| 2 | 研发部 | 1 | 2 | 研发部 | 1 |
+----+-----------+-----------+----+-----------+-----------+
1 row in set (0.00 sec)
(2)一个 CTE 引用另一个 CTE
mysql> with cte1 as (select * from `department` where id = 1),-> cte2 as (select * from cte1)-> select *-> from cte2;
+----+-----------+-----------+
| id | dept_name | parent_id |
+----+-----------+-----------+
| 1 | 总部 | 0 |
+----+-----------+-----------+
1 row in set (0.00 sec)
1.3 递归 CTE
1.3.1 递归 CTE 简介
递归CTE 是一个具有引用 CTE 名称本身的子查询的 CTE。递归 CTE 的语法为:
with recursive cte_name as (initial_query -- anchor member
union all
recursive_query -- recursive member that references to the cte name
)
select * from cte_name;
递归 CTE 由三个主要部分组成:
-
形成 CTE 结构的基本结果集的初始查询(initial_query),初始查询部分被称为锚成员。
-
递归查询部分是引用 CTE 名称的查询,因此称为递归成员。递归成员由一个 union all 或 union distinct 运算符与锚成员相连。
-
终止条件是当递归成员没有返回任何行时,确保递归停止。
递归 CTE 的执行顺序如下:
- 首先,将成员分为两个:锚点和递归成员。
- 接下来,执行锚成员形成基本结果集(
R0
),并使用该基本结果集进行下一次迭代。 - 然后,将
Ri
结果集作为输入执行递归成员,并将Ri + 1
作为输出。 - 之后,重复第三步,直到递归成员返回一个空结果集,换句话说,满足终止条件。
- 最后,使用
union all
运算符将结果集从R0
到Rn
组合。
1.3.2 递归成员限制
递归成功不能包含以下结构:
- 聚合函数,如 max、min、sum、avg、count 等。
- group by 子句
- order by 子句
- limit 子句
- distinct
上述约束不适用于锚点成员。 另外,只有在使用 union 运算符时,要禁止 distinct 才适用。 如果使用 union distinct 运算符,则允许使用 distinct。
另外,递归成员只能在其子句中引用 CTE 名称,而不是引用任何子查询。
1.3.3 递归 CTE 示例
with recursive cte_count (n)as (select 1union allselect n + 1from cte_countwhere n < 3)
select n from cte_count;
在此示例中,以下查询:
select 1
是作为基本结果集返回 1
的锚成员。
以下查询:
select n + 1
from cte_count
where n < 3
是递归成员,因为它引用了 cte_count 的 CTE 名称。递归成员中的表达式 < 3 是终止条件。当 n 等于 3,递归成员将返回一个空集合,将停止递归。
下图显示了上述 CTE 的元素:
递归 CTE 返回以下输出:
+------+
| n |
+------+
| 1 |
| 2 |
| 3 |
+------+
递归 CTE 的执行步骤如下:
- 首先,分离锚和递归成员。
- 接下来,锚定成员形成初始行
select 1
,因此第一次迭代在n = 1
时产生1 + 1 = 2
。 - 然后,第二次迭代对第一次迭代的输出
2
进行操作,并且在n = 2
时产生2 + 1 = 3
。 - 之后,在第三次操作
n = 3
之前,满足终止条件n <3
,因此查询停止。 - 最后,使用 union all 运算符组合所有结果集1,2和3。
1.3.4 使用递归 CTE 遍历分层数据
查部门 id = 2 的所有下级部门和本级:
mysql> with recursive cte_tab as (select id, dept_name, parent_id, 1 as level-> from department-> where id = 2-> union all-> select d.id, d.dept_name, d.parent_id, level + 1-> from cte_tab c-> inner join department d on c.id = d.parent_id-> )-> select *-> from cte_tab;
+------+-----------+-----------+-------+
| id | dept_name | parent_id | level |
+------+-----------+-----------+-------+
| 2 | 研发部 | 1 | 1 |
| 5 | Java组 | 2 | 2 |
| 6 | Python组 | 2 | 2 |
| 7 | 前端组 | 2 | 2 |
| 12 | Java1组 | 5 | 3 |
| 13 | Java2组 | 5 | 3 |
+------+-----------+-----------+-------+
6 rows in set (0.00 sec)
2. CTE 与 Derived Table
针对 from 子句里面的 subquery,MySQL 在不同版本中,是做过一系列的优化,接下来我们就来看看。
在 5.6 版本中
MySQL 会对每一个 Derived Table 进行物化,生成一个临时表保存 Derived Table 的结果,然后利用临时表来完成父查询的操作,具体如下:
mysql> explain-> select * from (select * from department where id <= 1000) t1 join (select * from department where id >= 990) t2 on t1.id = t2.id;
+----+-------------+------------+------------+--------+---------------+---------+---------+----------------------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------+------------+--------+---------------+---------+---------+----------------------------+------+----------+-------------+
| 1 | SIMPLE | department | NULL | range | PRIMARY | PRIMARY | 8 | NULL | 1 | 100.00 | Using where |
| 1 | SIMPLE | department | NULL | eq_ref | PRIMARY | PRIMARY | 8 | pointer_mall.department.id | 1 | 100.00 | NULL |
+----+-------------+------------+------------+--------+---------------+---------+---------+----------------------------+------+----------+-------------+
2 rows in set, 1 warning (0.01 sec)
在 5.7 版本中
MySQL 引入了 Derived Merge 新特性,允许符合条件的 Derived Table 中的子表与父查询的表进行合并,具体如下:
mysql> explain-> select * from (select * from department where id <= 1000) t1 join (select * from department where id >= 990) t2 on t1.id = t2.id;
+----+-------------+------------+------------+-------+---------------+-------------+---------+-------+---------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------+------------+-------+---------------+-------------+---------+-------+---------+----------+-------------+
| 1 | PRIMARY | <derived2> | NULL | ALL | NULL | NULL | NULL | NULL | 1900 | 100.00 | NULL |
| 1 | PRIMARY | <derived3> | NULL | ref | <auto_key0> | <auto_key0> | 8 | t1.id | 2563 | 100.00 | NULL |
| 3 | DERIVED | department | NULL | range | PRIMARY | PRIMARY | 8 | NULL | 4870486 | 100.00 | Using where |
| 2 | DERIVED | department | NULL | range | PRIMARY | PRIMARY | 8 | NULL | 1900 | 100.00 | Using where |
+----+-------------+------------+------------+-------+---------------+-------------+---------+-------+---------+----------+-------------+
4 rows in set, 1 warning (0.00 sec)
在 8.0 版本中
我们可以使用 CTE 实现,其执行计划也是和 Derived Table 一样
mysql> explain-> with t1 as (select * from department where id <= 1000),-> t2 as (select * from department where id >= 990)-> select * from t1 join t2 on t1.id = t2.id;
+----+-------------+------------+------------+--------+---------------+---------+---------+----------------------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------+------------+--------+---------------+---------+---------+----------------------------+------+----------+-------------+
| 1 | SIMPLE | department | NULL | range | PRIMARY | PRIMARY | 8 | NULL | 1 | 100.00 | Using where |
| 1 | SIMPLE | department | NULL | eq_ref | PRIMARY | PRIMARY | 8 | pointer_mall.department.id | 1 | 100.00 | NULL |
+----+-------------+------------+------------+--------+---------------+---------+---------+----------------------------+------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)
从测试结果来看,CTE 似乎是 Derived Table 的一个替代品?其实不是的,虽然 CTE 内部优化流程与 Derived Table 类似,但是两者还是区别的,具体如下:
-
一个 CTE 可以引用另一个 CTE
-
CTE 可以自引用
-
CTE 在语句级别生成临时表,多次调用只需要执行一次,提高性能
从上面介绍可以知道,CTE 一方面可以非常方便进行 SQL 开发,另一方面也可以提升 SQL 执行效率。
相关文章:

【MySQL】MySQL 8.0 新特性之 - 公用表表达式(CTE)
MySQL 8.0 新特性之 - 公用表表达式(CTE)1. 公用表表达式(CTE) - WITH 介绍1.1 公用表表表达式1.1.1 什么是公用表表达式1.1.2 CTE 语法1.1.3 CTE示例1.3 递归 CTE1.3.1 递归 CTE 简介1.3.2 递归成员限制1.3.3 递归 CTE 示例1.3.4…...
基础面试题:C++中如何理解const修饰符
面试题目:1、题 int i10; const int*p &i; int *const* p &i; const在不同位置有什么不 同 2、const 修饰类成员变量是有什么特殊要求 3、const 修饰类成员函数会发什么 4、const 对象有什么意义 目录 前言 一、const的意义 二、const使用规则 1.初始化…...

在RT-Thread STM32F407平台下配置SPI flash为U盘
记录下SPI Flash U盘实现过程中踩过的坑,与您分享。前提条件是,需要先将SPI Flash 配置到elm fal文件系统,并挂载成功。如下图然后开始配置USB1,在CubeMX,选择SUB_OTG_FS2 选择USB Device3,确认USB时钟为48…...

数据存储技术复习(二)未完
module3存储是数据中心内的核心元素。请说明常用的存储选项及其特点。磁盘驱动器:具有很大的存储容量,随机读/写访问闪存驱动器:使用半导体介质,提供高性能,低功耗2.若某磁盘驱动器显示每个磁道有八个扇区&…...

使用 QuTrunk+Amazon Deep Learning AMI(TensorFlow2)构建量子神经网络
量子神经网络是基于量子力学原理的计算神经网络模型。1995年,Subhash Kak 和 Ron Chrisley 独立发表了关于量子神经计算的第一个想法,他们致力于量子思维理论,认为量子效应在认知功能中起作用。然而,量子神经网络的典型研究涉及将…...

python selenium浏览器复用技术
使用selenium 做web自动化的时候,经常会遇到这样一种需求,是否可以在已经打开的浏览器基础上继续运行自动化脚本? 这样前面的验证码登录可以手工点过去,后面页面使用脚本继续执行,这样可以解决很大的一个痛点。 命令行…...

第二章:创建虚拟机
创建Windows server:首先第一步就是打开我们的vm,然后找到上一章讲的主页图标创建新的虚拟机。点击这上面类似的,然后转站。博文地址:https://blog.csdn.net/ryduijftgvhj/article/details/127934939?spm1001.2014.3001.5502视频…...

码上【call,apply,bind】的手写
一、call (1)官方用法 call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。 语法:function.call(要绑定的this值,参数,参数,…)。不一定这些参数都需要,这些参数都…...

代谢组学Nature子刊!抑郁症居然“男女有别”,脑膜淋巴管起关键作用!
文章标题:A functional role of meningeal lymphatics in sex difference of stress susceptibility in mice 发表期刊:Nature Communications 影响因子:17.694 发表时间:2022年8月 作者单位:中山大学中山医学院 …...

nacos配置中心搭建
网站每次更新版本都有短暂暂停,影响用户使用,返回经常不可用,需要改进 需要实现高可用,搭建负载均衡,实现jenkinsnacos不停机部署 nacos搭建预备环境准备 64 bit OS,支持 Linux/Unix/Mac/Windows&#x…...

uni-app低成本封装一个取色器组件
在uni-ui中找不到对应的工具 后面想想也是 移动端取色干什么? 没办法 也挂不住特殊需求 因为去应用市场下载 这总东西 又不是很有必要 那么 下面这个组件或许能解决您的烦恼 <template><view class"content"><view class"dialog&…...

APP 怎么免费接入 MobPush
1、获取 AppKey 申请 Appkey 的流程,请点击 http://bbs.mob.com/thread-8212-1-1.html?fromuid70819 2、下载 SDK 下载解压后,如下图: 目录结构 (1)Sample:演示Demo。(2)SDK&am…...

XGBoost
目录 1.XGBoost推导示意图 2.分裂节点算法 Weighted Quantile Sketch 3.对缺失值得处理 1.XGBoost推导示意图 XGBoost有两个很不错得典型算法,分别是用来进行分裂节点选择和缺失值处理 2.分裂节点算法 Weighted Quantile Sketch 对于特征切点点得选择ÿ…...

你是什么时候从轻视到高看软件测试的?
刚开始学软件测试很轻视,因为我那时很无知,这也是那时绝大多数人员的心态,那时中国最讲究“编程才是硬道理”。 如今却非常热爱软件测试,包括软件测试工具,方法,理论,技术。因为我在3年的测试工…...

基于ssm的航空售票系统
博主介绍:java高级开发,从事互联网行业六年,熟悉各种主流语言,精通java、python、php、爬虫、web开发,已经从做了六年的毕业设计程序开发,开发过上千套毕业设计程序,没有什么华丽的语言…...
滑动窗口最大值
给定一个数组 nums 和滑动窗口的大小 k,请找出所有滑动窗口里的最大值。 示例: 输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3 输出: [3,3,5,5,6,7] 解释: 滑动窗口的位置 最大值 --------------- ----- [1 3 -1] -3 5 3 6 7 3 …...
接口文档参考示例
接口文档参考示例 用户登录 - POST /api/login/ 接口说明:登录成功后,会生成或更新用户令牌(token)。 使用帮助:测试数据库中预设了四个可供使用的账号,如下表所示。 Untitled 请求参数: Untitled 响应信息: 登录成功: {"code": 30000, "message&qu…...

2010-2019年290个城市经济发展与环境污染数据
2010-2019年290个城市经济发展与环境污染数据 1、时间:2010-2019年 2、统计口径:全市 3、来源:城市统计NJ,缺失情况与年鉴一致 4、指标包括: 综合经济:地区生产总值、人均地区生产总值、地区生产总值增…...

web开发
目录 使用Idea搭建Web项目 使用Idea开发Web项目基本知识 tomcat配置信息 HTML /CSS 开发主页 Servlet 学习和掌握的内容: HTML/CSSServlet MVC模式和Web开发数据库基本应用和JDBC应用软件项目开发流程 环境及工具版本: Windows10,JDK1.8 Idea2…...

【数据结构】优先级队列----堆
优先级队列----堆优先级队列堆堆的创建堆的插入:堆的删除:PriorityQueue的特性PriorityQueue的构造与方法优先级队列 优先级队列: 不同于先进先出的普通队列,在一些情况下,优先级高的元素要先出队列。而这种队列需要提…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区。编辑器中应用变更时的操作范围,就是以模型选区为基准来…...

安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...

关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
三体问题详解
从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解…...
python报错No module named ‘tensorflow.keras‘
是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...
第7篇:中间件全链路监控与 SQL 性能分析实践
7.1 章节导读 在构建数据库中间件的过程中,可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中,必须做到: 🔍 追踪每一条 SQL 的生命周期(从入口到数据库执行)&#…...
探索Selenium:自动化测试的神奇钥匙
目录 一、Selenium 是什么1.1 定义与概念1.2 发展历程1.3 功能概述 二、Selenium 工作原理剖析2.1 架构组成2.2 工作流程2.3 通信机制 三、Selenium 的优势3.1 跨浏览器与平台支持3.2 丰富的语言支持3.3 强大的社区支持 四、Selenium 的应用场景4.1 Web 应用自动化测试4.2 数据…...