SQL关键字三分钟入门:WITH —— 公用表表达式让复杂查询更清晰

在实际的数据库开发和分析中,我们常常会遇到复杂的多层嵌套查询,这样的 SQL 语句不仅难以阅读,也容易出错。

这时候就需要使用一个非常实用又优雅的关键字 ------ WITH

它可以帮助我们将复杂的子查询提取出来并命名 ,从而提升代码可读性、复用性和维护性。这个功能也被称为 CTE(Common Table Expressions,公用表表达式)


1.什么是 WITH?

WITH 是 SQL 中用于定义临时结果集的关键字。这些临时结果集可以在后续查询中像普通表一样被引用,并且只在当前查询执行期间存在。

你可以把它理解为:"先写好一个中间结果,后面可以直接拿来用"。


2.基本语法

sql 复制代码
WITH cte_name AS (
    -- 子查询内容
    SELECT ...
)
-- 后续主查询中使用 cte_name
SELECT * FROM cte_name;
  • cte_name 是你给中间结果集起的名字。
  • 可以定义多个 CTE,用逗号分隔。

3.示例讲解

假设我们有一个 orders 表,记录了订单信息:

order_id customer_id amount
1 1 2999
2 2 499
3 1 199
4 3 899

示例1:计算每个客户的订单总金额(简单 CTE 使用)

sql 复制代码
WITH customer_totals AS (
    SELECT customer_id, SUM(amount) AS total_amount
    FROM orders
    GROUP BY customer_id
)
SELECT *
FROM customer_totals
WHERE total_amount > 500;
结果:
customer_id total_amount
1 3198
3 899

👉 这里我们先定义了一个 CTE customer_totals 来计算每位客户的总消费金额,然后主查询筛选出金额大于500的客户。


示例2:多个 CTE 的使用(分步处理复杂逻辑)

sql 复制代码
WITH
-- 第一步:统计每位客户的总消费
customer_totals AS (
    SELECT customer_id, SUM(amount) AS total_amount
    FROM orders
    GROUP BY customer_id
),
-- 第二步:根据总消费划分客户等级
customer_levels AS (
    SELECT customer_id, total_amount,
    CASE
        WHEN total_amount > 1000 THEN '高级客户'
        WHEN total_amount BETWEEN 500 AND 1000 THEN '中级客户'
        ELSE '普通客户'
    END AS level
    FROM customer_totals
)
-- 最终查询:展示客户等级信息
SELECT * FROM customer_levels;
结果:
customer_id total_amount level
1 3198 高级客户
2 499 普通客户
3 899 中级客户

通过多个 CTE 分步骤处理,整个查询逻辑更加清晰易懂。


示例3:递归 CTE(以员工层级为例)

递归 CTE 是 WITH 的一种高级用法,常用于处理树形结构或层级数据(如组织架构、分类目录等)。

假设我们有一个 employees 表:

employee_id name manager_id
1 张三 NULL
2 李四 1
3 王五 2
sql 复制代码
WITH RECURSIVE employee_hierarchy AS (
    -- 初始查询:没有上级的员工(即 CEO)
    SELECT employee_id, name, manager_id, CAST(name AS TEXT) AS hierarchy_path
    FROM employees
    WHERE manager_id IS NULL

    UNION ALL

    -- 递归部分:查找下属员工
    SELECT e.employee_id, e.name, e.manager_id,
           CAST(eh.hierarchy_path || ' → ' || e.name AS TEXT)
    FROM employees e
    INNER JOIN employee_hierarchy eh ON e.manager_id = eh.employee_id
)
SELECT * FROM employee_hierarchy;
结果:
employee_id name manager_id hierarchy_path
1 张三 NULL 张三
2 李四 1 张三 → 李四
3 王五 2 张三 → 李四 → 王五

这个例子展示了如何用递归 CTE 构建一个组织层级路径,非常适合处理树状结构数据。


对比项 使用 WITH(CTE) 不使用 CTE(嵌套子查询)
可读性 更高,结构清晰 较低,嵌套多层时难读
复用性 可多次引用 每次都要重复写
调试方便性 易于单独测试每个 CTE 难以调试嵌套部分
递归支持 支持(RECURSIVE) 不支持
性能 与子查询基本一致,但逻辑优化后可能更好 视具体实现而定

4. 总结对比表

功能 SQL 示例
定义单个 CTE WITH cte AS (...) SELECT * FROM cte;
定义多个 CTE WITH a AS (...), b AS (...) SELECT * FROM a JOIN b...
递归 CTE WITH RECURSIVE ...
提高代码可读性 将复杂查询拆分为多个逻辑块
支持重用 同一查询中可多次引用 CTE 名
相关推荐
技术吧3 分钟前
MySQL功能模块探秘:数据库世界的奇妙之旅
数据库·mysql
BillKu3 分钟前
Java读取Excel日期内容
java·开发语言·excel
ai小鬼头8 分钟前
如何重装旁路由系统并优化AIStarter部署:一步步教程
java·css·github
℡余晖^9 分钟前
Mysql默认存储引擎InnoDB和底层数据结构
数据库·mysql
笑衬人心。24 分钟前
Hashtable 与 HashMap 的区别笔记
java·数据结构·笔记
金心靖晨26 分钟前
消息中间件优化高手笔记
java·数据库·笔记
程序员JerrySUN32 分钟前
Linux 文件系统实现层详解:原理、结构与驱动衔接
android·linux·运维·数据库·redis·嵌入式硬件
鼠鼠我捏,要死了捏1 小时前
MongoDB性能优化实战指南:原理、实践与案例
数据库·mongodb·性能优化
古井无波 20241 小时前
ARMv8.1原子操作指令(ll_sc/lse)
数据库
lemon_sjdk1 小时前
Java飞机大战小游戏(升级版)
java·前端·python