CTE查询
参考:https://blog.csdn.net/xwxty/article/details/153417525。
·
CTE查询的概念
CTE(Common Table Expression,通用表表达式)是在SQL中用WITH子句定义的命名临时结果集,它的作用域仅限当前 SQL 语句执行期间,适合简化复杂查询、避免重复子查询,还支持递归场景。
应用场景:
1、如果需要再一个SQL里面多次引用同一个子查询,使用CTE只需要定义一次(典型)
2、类似视图一样,但是不想把SQL语句保存到数据库中(随差随丢)。
3、递归实现
基本语法:




特点:
- 临时性:不存储在磁盘,仅在查询执行时动态生成,执行结束后立即释放。
- 可读性:通过命名将复杂子查询模块化,让逻辑更直观
- 递归能力:支持递归查询(需
RECURSIVE关键字),是处理树形结构(如组织架构)、序列生成的唯一简洁方式。 - 作用域:仅在定义它的 SQL 语句中有效,无法被其他独立查询调用(区别于临时表)。
- 复用性:同一查询中可多次引用同一 CTE,避免重复编写子查询
使用场景和语法
单CTE
WITH 结果集名称 (列名1, 列名2, ...) -- 列名可选,默认继承子查询列名
AS (
-- 子查询:生成临时结果集的逻辑(支持SELECT/JOIN/WHERE等任意查询语法)
SELECT 列1, 列2
FROM 表名
WHERE 过滤条件
)
-- 主查询:像使用普通表一样引用CTE
SELECT * FROM 结果集名称;
- WITH 子句:用于定义一个或多个临时命名的结果集,这些结果集仅在当前 SQL 语句执行期间有效。
- AS (...):括号内的子查询负责生成临时结果集的数据。
- 主查询:在
WITH子句之后,可以像使用普通表一样,通过名称引用这个临时结果集进行后续查询。
示例1:


示例2:
-- 创建业务表
CREATE TABLE IF NOT EXISTS users (
id INT, -- 用户ID
name VARCHAR(10) -- 用户名
);
INSERT INTO users (id, name) VALUES (1, '小明'), (2, '小红');
-- 核心:最简CTE查询(仅筛选+查询)
WITH user_cte AS (
-- CTE子查询:仅筛选id=1的用户,只查name字段
SELECT name FROM users WHERE id = 1
)
-- 主查询:直接查CTE的结果(无任何统计/计算)
SELECT * FROM user_cte;
返回结果如下:
name
-------
小明
(1 row)
多CTE
多 CTE(Multiple Common Table Expressions)指的是在同一个WITH子句中 定义两个或以上的临时结果集(CTE),这些 CTE 共享同一个查询上下文,可独立使用也可相互依赖,本质是把多个独立的临时数据集 “打包” 在一次查询中,让复杂逻辑更清晰。
语法:
WITH
cte_name1 AS (子查询1), -- 第一个CTE:末尾必须加英文逗号
cte_name2 AS (子查询2), -- 中间CTE:依次加逗号
cte_name3 AS (子查询3) -- 最后一个CTE:末尾无逗号
-- 主查询:可关联/合并所有CTE结果
SELECT * FROM cte_name1 JOIN cte_name2 ON 关联条件;
示例:
CREATE TABLE IF NOT EXISTS products (
id INT, -- 商品ID
name VARCHAR(20),-- 商品名
price DECIMAL(8,2), -- 价格
category VARCHAR(10) -- 分类
);
INSERT INTO products VALUES
(1, 'T恤', 59.9, '服饰'),
(2, '牛仔裤', 129.9, '服饰'),
(3, '保温杯', 89.9, '日用品'),
(4, '毛巾', 19.9, '日用品');
-- 多CTE核心逻辑:分别统计不同分类的商品数
WITH
-- CTE1:统计服饰类商品数量
clothing_count AS (
SELECT COUNT(*) AS cloth_num FROM products WHERE category = '服饰'
),
-- CTE2:统计日用品类商品数量(和CTE1无依赖)
daily_count AS (
SELECT COUNT(*) AS daily_num FROM products WHERE category = '日用品'
)
-- 主查询:合并两个CTE的结果
SELECT cloth_num, daily_num FROM clothing_count, daily_count;
返回结果如下:
cloth_num | daily_num
----------|----------
2 | 2
(1 row)
递归CTE
递归 CTE 是 CTE 的进阶形态,通过RECURSIVE关键字实现自引用查询,专门用于处理层级 / 树形结构数据(如组织架构、商品分类、评论楼中楼)或序列生成(如生成连续日期 / 数字)。
它的核心是 “递推” 思想:
- 锚点(Anchor):定义查询的起始点(基础数据,非递归部分);
- 递归体(Recursive Term):引用自身,基于锚点数据迭代查询,直到无新数据返回;
- 终止条件:无需显式定义,当递归体查询返回空结果时,自动终止。
语法:
WITH RECURSIVE cte_name (列名1, 列名2, ...) AS (
-- 1. 锚点成员:初始查询(非递归,必须有且无自引用)
SELECT 列1, 列2 FROM 表名 WHERE 初始条件
UNION ALL -- 连接锚点和递归体(常用UNION ALL,避免去重损耗性能)
-- 2. 递归成员:引用CTE自身,实现迭代
SELECT t.列1, t.列2
FROM 原表 t
JOIN cte_name r ON t.关联列 = r.关联列 -- 核心:原表与CTE自身关联
WHERE 递归过滤条件 -- 可选,限制递归范围
)
-- 3. 主查询:读取递归结果
SELECT * FROM cte_name;
递归 CTE 的执行原理:
递归 CTE 的执行过程像 “循环迭代”,步骤如下:
- 先执行锚点成员,生成第一批结果,存入临时结果集;
- 执行递归成员:用临时结果集的数据关联原表,生成新结果;
- 若新结果非空,将其加入临时结果集,重复步骤 2;若为空,终止递归;
- 主查询读取最终的临时结果集,返回所有数据。
示例:
-- 递归CTE:生成1到5的连续数字
WITH RECURSIVE num_cte AS (
-- 锚点:起始数字1
SELECT 1 AS num
UNION ALL
-- 递归:数字+1,直到5
SELECT num + 1 FROM num_cte WHERE num < 5
)
SELECT num FROM num_cte;
返回结果如下:
num
-----
1
2
3
4
5
(5 rows)
更多推荐



所有评论(0)