MySql的CTE表达式
概述
mysql8.0之后新增了with语法,也被称作为公用表表达式(CTE),它是一个临时命名的结果集,仅在单个语句的执行范围内存在,并且在后续的sql中可以重复使用这个结果集。同时CTE分为递归CTE和非递归CTE。CTE的出现简化了复杂查询语句的编写,提高了sql性能。
CTE语法
CTE的结构包括名称、可选列和定义CTE的查询这三部分组成。使用with关键字连接一个或多个逗号分隔的查询语句组成了CTE。下面是一个CTE的例子:
1 | WITH cte1 AS ( SELECT 1 ), |
上面的例子中定义了两个CTE,可以通过这两个CTE的名称来访问他们。当然了我们也可以给CTE的列起一个名称
1 | WITH cte ( n ) AS ( SELECT 1 UNION SELECT 2 ) |
同时我们也可以在其它CTE中引用另一个CTE
1 | WITH cte1 AS ( SELECT 1 UNION SELECT 2 ), |
递归CTE
递归CTE是具有引用其自己名称的子查询的表达式。它和非递归CTE的不同之处在于非递归CTE的结果集是某个select返回的结果,而递归CTE的结果集是在其自身第一行的基础上递归生成接下来的其他行直到满足某个条件为止:
1 | WITH RECURSIVE cte (n) AS |
执行以上sql将会返回一个自增的列
1 | 1 |
递归CTE子查询有两个部分,由UNION [ALL] 或 UNION DISTINCT组成:
1 | SELECT ... -- 初始行 |
- 第一个select生成CTE中的初始行,该select只会执行一次。
- 第二个select通过引用其from子句中的CTE名称来生成其他行和递归。当此部分不产生新行时,递归结束。因此,递归CTE由非递归 SELECT部分和递归SELECT部分组成。
- 递归部分的每次迭代仅对前一次递归产生的行进行操作,每次递归前都会先判断满足条件才会递归。
例如上面递归中的SELECT n + 1 FROM cte WHERE n < 5
,第一次递归是根据初始行1进行自增,然后每次获取上一次递归的值进行递增直到n不超过5。
CTE例子
通常我们会有这样一个需求,统计前xx个月的数据。但是很有可能表中的数据并没有覆盖到每个月,此时我们就需要生成一个临时的月份表通过left join来关联业务表进行统计。下面是一个生成前24个月月份的例子:
1 | WITH RECURSIVE months24 ( n, MONTH ) AS ( |
执行结果:
1 | 201708 |
总结
利用CTE我们可以将复杂查询语句进行简化,同时能够重复利用CTE的结果集,提高了sql的性能。