MySQL 8.0新特性--CTE(一)
发表于:2025-11-11 作者:千家信息网编辑
千家信息网最后更新 2025年11月11日,1、CTE简介MySQL从8.0开始支持CTE,慢慢地向Oracle学习,CTE确实是个很好用的东西,特别是针对OLAP类型的SQL,可以大大简化,优化SQL.那么什么是CTE呢?个人理解:CTE(c
千家信息网最后更新 2025年11月11日MySQL 8.0新特性--CTE(一)
1、CTE简介
MySQL从8.0开始支持CTE,慢慢地向Oracle学习,CTE确实是个很好用的东西,特别是针对OLAP类型的SQL,可以大大简化,优化SQL.
那么什么是CTE呢?
个人理解:CTE(common table expression)是一个临时的结果集,类似一个函数,一旦定义好,可以多次调用。
2、CTE语法
with_clause: WITH [RECURSIVE] cte_name [(col_name [, col_name] ...)] AS (subquery) [, cte_name [(col_name [, col_name] ...)] AS (subquery)] ...
(1)列别名可以在不同的位置定义
mysql> WITH cte (col1, col2) AS -> ( -> SELECT 1, 2 -> UNION ALL -> SELECT 3, 4 -> ) -> SELECT col1, col2 FROM cte;+------+------+| col1 | col2 |+------+------+| 1 | 2 || 3 | 4 |+------+------+2 rows in set (0.00 sec)等价与:mysql> WITH cte AS -> ( -> SELECT 1 AS col1, 2 AS col2 -> UNION ALL -> SELECT 3, 4 -> ) -> SELECT col1, col2 FROM cte;+------+------+| col1 | col2 |+------+------+| 1 | 2 || 3 | 4 |+------+------+2 rows in set (0.00 sec)
(2) CTE用在Select操作
mysql> create table t1(a int,b int);mysql> insert into t1 values(1,1),(2,2),(3,3);mysql> with t as (select a+2 c,b from t1) select c,b from t;+------+------+| c | b |+------+------+| 3 | 1 || 4 | 2 || 5 | 3 |+------+------+3 rows in set (0.00 sec)
(3)CTE用在DML操作
mysql> with t as (select a+2 as a,b from t1) update t1,t set t1.a=t.a+10 where t1.a=t.a;mysql> select * from t1;+------+------+| a | b |+------+------+| 1 | 1 || 2 | 2 || 13 | 3 |+------+------+3 rows in set (0.00 sec)mysql> with t as (select a+2 as a,b from t1) delete t1 from t1,t where t1.a=t.a;mysql> select * from t1;+------+------+| a | b |+------+------+| 1 | 1 || 2 | 2 |+------+------+2 rows in set (0.00 sec)mysql> insert into t1 with t as (select 10*a as a,b from t1) select * from t;mysql> select * from t1;+------+------+| a | b |+------+------+| 1 | 1 || 2 | 2 || 3 | 3 || 10 | 1 || 20 | 2 || 30 | 3 |+------+------+6 rows in set (0.00 sec)
3、CTE可以优化SQL
(1)下面第一条SQL可以改写成如下两种CTE简化形式
mysql> select count(*) from employees e1 left join (select * from employees) e2 on e1.emp_no=e2.emp_no left join (select * from employees) e3 on e2.emp_no=e3.emp_no; mysql> with e2 as (select * from employees), e3 as (select * from employees) select count(*) from employees e1 left join e2 on e1.emp_no=e2.emp_no left join e3 on e2.emp_no=e3.emp_no; mysql> with e as(select * from employees) select count(*) from employees e1 left join e e2 on e1.emp_no=e2.emp_no left join e e3 on e2.emp_no=e3.emp_no;
(2)CTE的本质是子查询,所以子查询的一些特性都适用,如子查询合并。
mysql> desc with e as(select /*+ set_var(optimizer_switch='derived_merge=off')*/ * from employees) -> select count(*) from employees e1 -> left join e e2 on e1.emp_no=e2.emp_no -> left join e e3 on e2.emp_no=e3.emp_no;+----+-------------+------------+------------+-------+---------------+-------------+---------+------------------+--------+----------+-------------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |+----+-------------+------------+------------+-------+---------------+-------------+---------+------------------+--------+----------+-------------+| 1 | PRIMARY | e1 | NULL | index | NULL | PRIMARY | 4 | NULL | 299512 | 100.00 | Using index || 1 | PRIMARY || NULL | ref | | | 4 | testdb.e1.emp_no | 10 | 100.00 | NULL || 1 | PRIMARY | | NULL | ref | | | 4 | e2.emp_no | 10 | 100.00 | NULL || 2 | DERIVED | employees | NULL | ALL | NULL | NULL | NULL | NULL | 299512 | 100.00 | NULL |+----+-------------+------------+------------+-------+---------------+-------------+---------+------------------+--------+----------+-------------+4 rows in set, 2 warnings (0.00 sec)
(3)CTE可以起到减少插入临时表数据,优化SQL的作用
mysql> flush status;Query OK, 0 rows affected (0.02 sec)mysql> select /*+ set_var(optimizer_switch='derived_merge=off')*/ * from -> (select * from t_group) t1 -> join (select * from t_group) t2 -> on t1.emp_no=t2.emp_no;+--------+---------+------------+------------+--------+---------+------------+------------+| emp_no | dept_no | from_date | to_date | emp_no | dept_no | from_date | to_date |+--------+---------+------------+------------+--------+---------+------------+------------+| 22744 | d006 | 1986-12-01 | 9999-01-01 | 22744 | d006 | 1986-12-01 | 9999-01-01 || 24007 | d005 | 1986-12-01 | 9999-01-01 | 24007 | d005 | 1986-12-01 | 9999-01-01 || 30970 | d005 | 1986-12-01 | 2017-03-29 | 30970 | d005 | 1986-12-01 | 2017-03-29 || 31112 | d002 | 1986-12-01 | 1993-12-10 | 31112 | d002 | 1986-12-01 | 1993-12-10 || 40983 | d005 | 1986-12-01 | 9999-01-01 | 40983 | d005 | 1986-12-01 | 9999-01-01 || 46554 | d008 | 1986-12-01 | 1992-05-27 | 46554 | d008 | 1986-12-01 | 1992-05-27 || 48317 | d008 | 1986-12-01 | 1989-01-11 | 48317 | d008 | 1986-12-01 | 1989-01-11 || 49667 | d007 | 1986-12-01 | 9999-01-01 | 49667 | d007 | 1986-12-01 | 9999-01-01 || 50449 | d005 | 1986-12-01 | 9999-01-01 | 50449 | d005 | 1986-12-01 | 9999-01-01 || 10004 | d004 | 1986-12-01 | 9999-01-01 | 10004 | d004 | 1986-12-01 | 9999-01-01 |+--------+---------+------------+------------+--------+---------+------------+------------+10 rows in set (0.00 sec)mysql> show status like '%handler_write%';+---------------+-------+| Variable_name | Value |+---------------+-------+| Handler_write | 20 |+---------------+-------+1 row in set (0.00 sec)mysql> flush status;Query OK, 0 rows affected (0.02 sec)mysql> with t as(select /*+ set_var(optimizer_switch='derived_merge=off')*/ * from t_group) -> select * from t t1 -> join t t2 on t1.emp_no=t2.emp_no;+--------+---------+------------+------------+--------+---------+------------+------------+| emp_no | dept_no | from_date | to_date | emp_no | dept_no | from_date | to_date |+--------+---------+------------+------------+--------+---------+------------+------------+| 22744 | d006 | 1986-12-01 | 9999-01-01 | 22744 | d006 | 1986-12-01 | 9999-01-01 || 24007 | d005 | 1986-12-01 | 9999-01-01 | 24007 | d005 | 1986-12-01 | 9999-01-01 || 30970 | d005 | 1986-12-01 | 2017-03-29 | 30970 | d005 | 1986-12-01 | 2017-03-29 || 31112 | d002 | 1986-12-01 | 1993-12-10 | 31112 | d002 | 1986-12-01 | 1993-12-10 || 40983 | d005 | 1986-12-01 | 9999-01-01 | 40983 | d005 | 1986-12-01 | 9999-01-01 || 46554 | d008 | 1986-12-01 | 1992-05-27 | 46554 | d008 | 1986-12-01 | 1992-05-27 || 48317 | d008 | 1986-12-01 | 1989-01-11 | 48317 | d008 | 1986-12-01 | 1989-01-11 || 49667 | d007 | 1986-12-01 | 9999-01-01 | 49667 | d007 | 1986-12-01 | 9999-01-01 || 50449 | d005 | 1986-12-01 | 9999-01-01 | 50449 | d005 | 1986-12-01 | 9999-01-01 || 10004 | d004 | 1986-12-01 | 9999-01-01 | 10004 | d004 | 1986-12-01 | 9999-01-01 |+--------+---------+------------+------------+--------+---------+------------+------------+10 rows in set, 1 warning (0.00 sec)mysql> show status like '%handler_write%';+---------------+-------+| Variable_name | Value |+---------------+-------+| Handler_write | 10 |+---------------+-------+1 row in set (0.00 sec)
CTE除了一般功能外,还可以实现递归一些复杂SQL需求,参考MySQL 8.0新特性--CTE(二)
参考链接
13.2.13 WITH Syntax (Common Table Expressions)
查询
特性
参考
不同
复杂
东西
个人
位置
作用
函数
别名
功能
形式
数据
本质
等价
简介
类型
结果
语法
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
zencart 数据库
服务器操作记录
燃烧的远征比格沃斯服务器咋样
网络安全宣传日活动总结讲话稿
软件开发劳务资质如何办理
网络安全的思想汇报
3数据库多条记录合并
服务器日志ip
软件开发企业 开发费用
软件开发公司商标取名
学校网络安全应急技术支撑
数据库查询代码和截图
华硕 服务器主板 图纸
电视显示数据库异常无法备份
牛客华为服务器广播
数据库时间类型默认值
张店销售库存软件开发
光伏电站网络安全检查
显卡检测软件开发
数据库创建架构失败
电力组态软件开发工具
网络安全公司成立的背景
四级网络技术考核内容
资源数据库
在数据库中限权可分为
容联科技网络安全
软件开发助理工程师多久能升级
无退休人员数据库
数据库培训都包括什么
浪潮服务器默认ip是多少