订阅更新

餐馆营业额 7 天滑动平均

SQL 实战 123 题 · 第 92 题 中等 约 2 分钟读完

LeetCode 1321 · 先按天汇总、滑动窗口、ROWS 与 RANGE

本文目录
  1. 面试怎么回答
  2. 题意
  3. 表结构
  4. 思路
  5. 参考解法
  6. 易错点

面试怎么回答

先 GROUP BY visited_on 求每天营业额,再 SUM(...) OVER (ORDER BY visited_on ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) 算 7 天合计,除以 7 保留两位,过滤掉前 6 天。如果日期可能断档,我会改成按日期的 RANGE 窗口。

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

题意

顾客消费表记录每个顾客每天的消费金额,餐馆每天至少有一位顾客。对每一天,计算包括当天在内的最近 7 天的营业总额,以及 7 天日均额(保留两位小数);不满 7 天的日期不输出。

表结构

  • Customer:customer_id、name、visited_on、amount;(customer_id, visited_on) 为主键

思路

先按天汇总出每天的营业额(一天可能有多个顾客),再对按天的结果做 7 行的滑动求和,除以 7 得到日均。前 6 天不满 7 天,用 LAG(日期, 6) 是否存在来判断,或者直接从最早日期 + 6 天开始输出。

参考解法

select  visited_on,amount,round(amount/7,2) average_amount
from (
    select visited_on,ant,lag(visited_on,6,null) over(order by visited_on) lg,
            sum(ant) over(order by visited_on rows between 6 PRECEDING and current row) amount
    from(
        select  visited_on  ,sum(amount) ant
        from Customer
        group by visited_on
    )t1
)t2
where lg is not null

易错点

  • 不先按天汇总,窗口里的 7 行是 7 条消费记录,不是 7 天。
  • 题目保证每天都有营业,所以 7 行等于 7 天;如果可能有空白日期,要用 RANGE BETWEEN INTERVAL 6 DAY PRECEDING AND CURRENT ROW。
刷题进度保存在当前浏览器