SQL 课程 16:使用 CTE 拆解查询

当一条 SQL 同时包含筛选、计算、分组和再次筛选时,所有逻辑挤在一起很容易读不懂。CTE(Common Table Expression,公共表表达式)可以先把中间结果命名,再在后面的查询中使用它。

可以把 CTE 想成一张只在本条 SQL 中临时存在的“中间表”:WITH 名称 AS (查询) 先准备数据,后面的 SELECT 再消费这份数据。它不会修改原始 CSV,也不会把中间结果永久保存。

本课会把商机分析拆成几个清晰阶段:先筛出已成交商机,再按销售人员或客户汇总,最后筛选和排序汇总结果。

用 WITH 命名中间结果
WITH 中间表名 AS (
  SELECT ...
  FROM ...
  WHERE ...
)
SELECT ...
FROM 中间表名;

CTE 先做准备,主查询再回答问题

如果每个指标都重复写 WHERE deal_stage = 'Won',查询会变长,也容易某一处漏写条件。可以先定义 won_opportunities,只保留已成交商机;后续查询面对的就是一张更小、更明确的中间表。

CTE 的名字应该表达它包含什么数据,例如 won_opportunities、agent_summary、monthly_won。好的名字会让 SQL 像一段业务说明,而不是一串难以维护的括号。

先准备已成交商机,再按销售人员汇总
WITH won_opportunities AS (
  SELECT sales_agent, close_value
  FROM sales_pipeline
  WHERE deal_stage = 'Won'
)
SELECT sales_agent,
       COUNT(*) AS won_opportunity_count,
       SUM(close_value) AS won_close_value
FROM won_opportunities
GROUP BY sales_agent;

小提醒:CTE 只在当前查询中有效。它不是 CREATE TABLE,不会给本地数据增加一张永久表。

多层 CTE:把不同粒度分开

产品分析经常需要先按人或客户汇总,再对汇总后的结果做筛选。例如“找出成交笔数至少 150 笔的销售人员”,150 是销售人员这一组的指标,不应该写进最初筛选每条商机的 WHERE 中。

第一层 CTE 处理明细,第二层 CTE 处理汇总,最后的 SELECT 处理展示和排序。每一层只负责一个问题,调试时也可以暂时把最后的 SELECT 改成查看中间结果。

CTE 分层的思路

阶段处理对象示例
明细层单条商机筛选 deal_stage = 'Won'
汇总层销售人员或客户分组COUNT、SUM、GROUP BY
展示层汇总后的结果阈值筛选、排序、取字段

CTE 不会改变分析口径

把一条查询拆成 CTE,并不会自动让结果更正确。仍然要检查 JOIN 是否重复计数、NULL 是否需要排除、金额是否只统计 Won。CTE 的价值是让这些口径更容易被看见和复用。

练习

每道题都要求使用一个或多个 CTE;系统验收最终结果,不按 SQL 文本判定,但字段、行数、数据和排序必须正确。

表格:sales_pipeline(商机)

查询返回 0 行。

显示第 00
1 / 1
正在准备浏览器内 SQL 数据库…