通过真实业务数据,练习产品分析 SQL。
SQL 课程 16:使用 CTE 拆解查询
当一条 SQL 同时包含筛选、计算、分组和再次筛选时,所有逻辑挤在一起很容易读不懂。CTE(Common Table Expression,公共表表达式)可以先把中间结果命名,再在后面的查询中使用它。
可以把 CTE 想成一张只在本条 SQL 中临时存在的“中间表”:WITH 名称 AS (查询) 先准备数据,后面的 SELECT 再消费这份数据。它不会修改原始 CSV,也不会把中间结果永久保存。
本课会把商机分析拆成几个清晰阶段:先筛出已成交商机,再按销售人员或客户汇总,最后筛选和排序汇总结果。
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 文本判定,但字段、行数、数据和排序必须正确。