餐馆营业额 7 天滑动平均
LeetCode 1321 · 先按天汇总、滑动窗口、ROWS 与 RANGE
面试怎么回答
先 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。