Mysql杂志(十五)——公用表达式CTE
公用表达式
公用表达式(Common Table Expression,简称CTE)是MySQL 8.0引入的一种临时命名结果集,它只在当前查询中有效。CTE可以被视为一个临时视图,仅在查询执行期间存在。
主要的作用有:提高SQL可读性:将复杂查询分解为多个逻辑部分、实现递归查询:处理层次结构数据(如组织结构、评论回复链)、替代子查询:简化嵌套查询结构、代码复用:在同一查询中多次引用同一结果集、替代视图:临时使用而不需要创建永久视图。下面是CTE与传统SQL和临时表的比较:
特性 | CTE | 临时表 | 传统子查询 |
---|---|---|---|
生命周期 | 仅当前查询 | 会话结束前 | 当前语句 |
存储 | 内存 | 磁盘/内存 | 内存 |
复用性 | 同一查询内可多次引用 | 会话内可复用 | 不可复用 |
索引 | 不支持 | 支持 | 不支持 |
性能 | 中等 | 大数据量时较好 | 简单查询快 |
可读性 | 最好 | 中等 | 差(嵌套深时) |
递归支持 | 支持 | 不支持 | 不支持 |
其实主包自己用下来的话觉得CTE还是非常快的,如果是哪种很多子查询互相嵌套的话,CTE的可读性和性能都要高于传统的SQL,相对于窗口函数、存储过程主包个人觉得这个CTE使用更加的容易和方便。
CTE语法结构
#基础语法
WITH cte_name [(column_list)] AS (subquery
)
SELECT * FROM cte_name;#多CTE语法
WITH cte1 AS (SELECT ...),cte2 AS (SELECT ... FROM cte1)
SELECT * FROM cte1 JOIN cte2 ...;#递归CTE
WITH RECURSIVE cte_name AS (-- 基础查询(锚成员)SELECT ... FROM table WHERE base_conditionUNION [ALL]-- 递归查询(递归成员)SELECT ... FROM table JOIN cte_name WHERE recursive_condition
)
SELECT * FROM cte_name;
CTE基础用法
-- 计算各部门平均工资高于公司平均工资的部门
WITH dept_avg AS (SELECT department_id, AVG(salary) AS avg_salaryFROM employeesGROUP BY department_id),company_avg AS (SELECT AVG(salary) AS avg_salary FROM employees)
SELECT d.department_id, d.avg_salary
FROM dept_avg d
JOIN company_avg c ON d.avg_salary > c.avg_salary;
其实很简单,我们把dept_avg当成一个临时表as后面就是子查询,然后我们再到主查询中使用它就可以了。
递归CTE用法
-- 查询组织架构层级
WITH RECURSIVE org_hierarchy AS (-- 基础查询:获取顶级节点SELECT id, name, parent_id, 1 AS levelFROM organizationWHERE parent_id IS NULLUNION ALL-- 递归查询:获取下级节点SELECT o.id, o.name, o.parent_id, h.level + 1FROM organization oJOIN org_hierarchy h ON o.parent_id = h.id
)
SELECT * FROM org_hierarchy ORDER BY level;
其实就是通过RECURSIVE这个关键字声明,当前的CTE可以被递归使用,如果不加这个关键词就没办法当前CTE使用(自己),其他的CTE还是可以使用的。
对比维度 | CTE的优点 | CTE的缺点 |
---|---|---|
可读性 | ✅ 将复杂查询分解为逻辑清晰的模块 | |
代码复用 | ✅ 同一查询中可多次引用同一CTE | |
功能特性 | ✅ 唯一能实现递归查询的SQL结构 | |
优化性能 | ✅ MySQL优化器能更好地处理CTE | ❌ 处理大数据量时可能不如临时表高效 |
视图替代 | ✅ 不需要创建永久视图即可获得类似效果 | |
生命周期 | ❌ 仅存在于当前查询,会话结束后自动消失 | |
索引支持 | ❌ 无法像临时表那样创建索引 | |
版本兼容 | ❌ MySQL 8.0+才完全支持,早期版本不可用 |
总结
这一篇主要讲了公用表达式CTE的用法和优缺点,是比临时表、视图、存储过程、窗口函数更加简单的一种高级写法,这篇内容比较少所以水一下吧。