MySQL 8.0新特性--CTE(一)
admin
2023-04-20 14:23:06
0次

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)


相关内容

热门资讯

空调连续工作多久需要停机休息 空调连续工作的时间取决于多个因素,包括空调的型号、功率、使用环境和维护情况等。一般来说,空调可以连续...
空调哪个符号是除湿的 空调除湿功能通常用一个水滴形状的符号表示。不同品牌和型号的空调遥控器可能会有所差异,但一般来说,除湿...
格力空调多长时间加一次氟利昂 1、一般情况下,空调对氟利昂的使用量是非常小的,所以在空调使用了四年左右的时候再考虑加也没问题。2、...
空调用多长时间需要加氟一次 一般情况下是五年。当出现以下这几种情况时,空调才需要加氟。1、空调的室内机和室外机各有两个接口,当接...
格调生活·C标思享荟:卡萨帝在... 9月12日的郑州龙湖金融岛,夜风轻拂,灯光璀璨。“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑...
品牌价值破千亿、高端份额持续领... 9月12日,“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑州站”在郑州龙湖金融岛举办。2026...
空调主板坏了修800还是换新的 空调主板坏了是修还是换新,需要考虑多个因素,以下是一些建议:1. 维修成本:如果维修费用较低,比如 ...
空调开多久需要休息多长时间 问题:空调开多久需要休息多长时间回答:1、在使用空调的过程中,一般空调开7~8个小时左右需要休息2~...
中央空调多长时间清洗一次 1、一般空调开机前清洗一次即可,空调开机中间时段再清洗一次,空调关机时清洗一次,这样比较合理。2、空...
中央空调氟利昂多久加一次 看空调制热和制冷程度,很多人的观点认为氟利昂必须一年放一次,其实这个观点是错误的,理解上面有点偏差,...