WEEK 02

第二批数据来了:多表世界

运营把后台的用户、商品、订单明细三张表导给你:「老板要按城市和品类看销售。」单张 orders 表答不了这些--你第一次要把多张表连起来查。月底还要交公司的第一份正式月报。
目标:多表报表查询不再靠试;能当场解释 LEFT JOIN 的过滤陷阱。
0 / 7 天
剧情 运营发来 users 表(1 万用户):「老板想知道都是哪些城市的人在买。」订单表里只有 user_id,你的第一次表连接。
练 · 65 min
  1. 跑 seed.sql「W2」段导入三张新表,count(*) 核对行数
  2. orders 连 users,让每笔订单带上用户名和城市
  3. 查「上海用户」的订单数:先过滤再连、连了再过滤各写一遍,对比结果
  4. 各城市的订单数和 GMV
  5. 故意把连接条件写成 user_id = user_id 不加表名限定,记下报错
过关能说清 JOIN ON 的条件在业务上表示什么、两个 user_id 分别属于谁。
专注视图 ->
剧情 明细数据到位(500 商品 / 12 万明细)。你一条查询漏写了连接条件,跑出几十亿行的组合,笔记本风扇狂转--笛卡尔积事故现场。
练 · 70 min
  1. 四表连接出订单明细:单号 / 用户名 / 商品名 / 数量 / 单价
  2. 验证结果行数 = order_items 行数,解释为什么
  3. 故意漏写一个连接条件:先笔算会出多少行,再加 LIMIT 跑一遍验证
  4. 统计每笔订单的商品种类数和总件数
  5. 把四表连接写成不带别名的版本,感受可读性差在哪里
过关四表连接一次写对,且结果行数与 order_items 行数一致(能解释为什么)。
专注视图 ->
剧情 月报初稿被老板打回:「那些还没支付的订单呢?」你用了 INNER JOIN,把没有匹配行的数据全丢了。今天专门搞懂 LEFT JOIN 的坑。
练 · 60 min
  1. 造两张 3 行小表,四种 JOIN 各跑一次,把结果抄进 notes.md
  2. 同一个 LEFT JOIN,条件分别放 ON 和 WHERE,对比行数并解释
  3. 查所有用户及其订单数,没下过单的显示 0
  4. 用 LEFT JOIN + IS NULL 查「从未下过单的用户」
  5. 构造一个 count(b.id) 与 count(*) 结果不同的查询,解释原因
过关用小表结果解释为什么 LEFT JOIN 把条件放 WHERE 会退化成 INNER JOIN。
专注视图 ->
剧情 老板的正式需求下来了:一张表里要同时看到总单、已付、取消和支付率--维度越来越多。
练 · 65 min
  1. 按「城市 × 状态」双维度统计订单数与 GMV
  2. 用 FILTER 在一条 SQL 里同时算:总单数、已支付单数、已取消单数
  3. 用 sum(case when ...) 再写一遍第 2 题,对比可读性
  4. 用 ROLLUP 输出「城市销售额 + 小计 + 总计」
  5. 算各城市客单价(GMV / 订单数),并回答:city 为 NULL 的用户算哪个口径
过关一条 SQL 输出「城市 | 总单 | 已付 | 取消 | 支付率」五列。
专注视图 ->
剧情 增长侧的同事问:有多少用户注册了却一单没下?你发现这本质是个集合问题。
练 · 70 min
  1. 同一查询用 UNION 和 UNION ALL 各跑一次,对比 EXPLAIN 里多出来的节点
  2. 用 EXCEPT 查「注册了但从未下过单」的用户
  3. 用 INTERSECT 查「既买过商品 1 也买过商品 2」的用户
  4. 用 DISTINCT ON (user_id) 取每个用户最新一单
  5. 用 LEFT JOIN 改写第 2 题,对比两种写法的执行计划
过关说出 UNION 相比 UNION ALL 多做了什么操作,因此何时该用哪个。
专注视图 ->
剧情 月底。老板要「公司经营月报」:品类、城市、复购、客单价……你一上午都在跟口径较劲。
练 · 95 min · 每题单条 SQL
  1. GMV 三个口径对账:全部订单 / 只算已支付 / 已支付且剔除负金额
  2. 本月每日订单数与 GMV,没有订单的日期要补 0
  3. 客单价最高的 TOP10 商品
  4. 下单超 24 小时仍未支付的订单明细
  5. 各城市 GMV 排名
  6. 从未下过单的注册用户数及其占比
  7. 每个用户的首单时间与首单金额
  8. 各状态订单的平均支付时长(paid_at 与 created_at 之差)
过关8 题全部单条 SQL 完成;第 1 题三个 GMV 口径的差额,每一笔都能说出来自哪。
专注视图 ->
剧情 月报交付。复盘这一周踩过的所有 JOIN 坑,来一场限时专项测评。
专项 12 题 · 110 min
  1. JOIN 之后 count 变多了,列出三种可能原因
  2. 一对多连接导致订单金额被重复累加,写出两种修复方案
  3. 用三种写法查「没有下过单的用户」并对比计划
  4. LEFT JOIN 后 count(b.id) 与 count(*) 结果不同,解释原因
  5. 剩余 8 题:LeetCode 中等难度多表题
过关12 题正确 ≥ 9 题;能画图解释一对多连接的金额翻倍问题。
专注视图 ->