CTE是SQL中定义临时结果集的语法结构,仅在当前查询有效,语法以WITH开头,支持递归查询与逻辑分层,提升可读性与维护性,但不存储数据、不跨语句复用。

CTE(Common Table Expression,公用表表达式)是SQL中用于定义临时结果集的语法结构,它不存储数据,只在当前查询中有效,写法清晰、逻辑分层,特别适合处理递归查询、复杂子查询或提升可读性。
CTE的基本语法和写法
CTE以WITH关键字开头,后跟一个别名和括号内的列名(可选),再用AS定义查询语句。多个CTE可用逗号分隔。
- 基本格式:WITH cte_name [(col1, col2, ...)] AS (SELECT ...) SELECT ... FROM cte_name;
- 列名可省略,系统会自动取子查询的字段名;显式声明更安全,尤其当子查询含表达式或函数时
- CTE只在紧随其后的单个SELECT/INSERT/UPDATE/DELETE语句中生效,不能跨语句复用
为什么用CTE而不是子查询或临时表
相比嵌套子查询,CTE让代码更易读、可维护;相比临时表,它无需创建/删除对象、不占用磁盘空间、无事务和权限开销。
- 嵌套子查询过深时(比如三层以上),逻辑难追踪;CTE把各层拆成命名步骤,一目了然
- 同一结果需多次引用?子查询要重复写,CTE只需定义一次,后面可多次FROM调用(注意:仍属单语句范围)
- 临时表适合大数据量中间结果复用或跨批次操作;CTE更适合轻量、一次性、逻辑解耦场景
递归CTE:处理树形或层级数据
递归CTE由锚点成员(起始查询)和递归成员(自引用JOIN)组成,必须用UNION ALL连接,且递归部分必须引用CTE自身名称。
- 典型用途:查部门上下级、BOM物料清单、评论回复链、组织架构遍历
- 必须设置终止条件,否则无限循环;SQL Server/PostgreSQL支持MAXRECURSION或LIMIT控制深度
- 示例(员工-上级关系):WITH org AS (SELECT id, name, manager_id FROM emp WHERE manager_id IS NULL UNION ALL SELECT e.id, e.name, e.manager_id FROM emp e INNER JOIN org o ON e.manager_id = o.id)
CTE使用的常见注意事项
CTE不是视图,也不保存元数据;它的行为高度依赖数据库实现,不同系统支持度略有差异。
- MySQL 8.0+、PostgreSQL、SQL Server、Oracle均原生支持;旧版MySQL(5.7及之前)不支持,需改用临时表或变量模拟
- CTE中的查询不一定会物化——优化器可能将其内联展开,性能不一定优于等价子查询,建议结合执行计划分析
- 不能在CTE定义中直接引用另一个尚未定义的CTE(顺序敏感),但可以链式定义:WITH a AS (...), b AS (SELECT ... FROM a), c AS (SELECT ... FROM b)
基本上就这些。CTE不是银弹,但掌握它能让SQL更干净、逻辑更扎实,尤其在报表开发和数据探查阶段很实用。










