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

发布于:2025-06-20 ⋅ 阅读:(17) ⋅ 点赞:(0)

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

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

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


 1.什么是 WITH?

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

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


 2.基本语法

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 使用)

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 的使用(分步处理复杂逻辑)

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
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 名

网站公告

今日签到

点亮在社区的每一天
去签到