SQL.LeetCode(1321)餐馆营业额变化增长

表: Customer

复制代码
+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| customer_id   | int     |
| name          | varchar |
| visited_on    | date    |
| amount        | int     |
+---------------+---------+
在 SQL 中,(customer_id, visited_on) 是该表的主键。
该表包含一家餐馆的顾客交易数据。
visited_on 表示 (customer_id) 的顾客在 visited_on 那天访问了餐馆。
amount 是一个顾客某一天的消费总额。

你是餐馆的老板,现在你想分析一下可能的营业额变化增长(每天至少有一位顾客)。

计算以 7 天(某日期 + 该日期前的 6 天)为一个时间段的顾客消费平均值。average_amount保留两位小数。

结果按 visited_on 升序排序

返回结果格式的例子如下。

示例 1:

复制代码
输入:
Customer 表:
+-------------+--------------+--------------+-------------+
| customer_id | name         | visited_on   | amount      |
+-------------+--------------+--------------+-------------+
| 1           | Jhon         | 2019-01-01   | 100         |
| 2           | Daniel       | 2019-01-02   | 110         |
| 3           | Jade         | 2019-01-03   | 120         |
| 4           | Khaled       | 2019-01-04   | 130         |
| 5           | Winston      | 2019-01-05   | 110         | 
| 6           | Elvis        | 2019-01-06   | 140         | 
| 7           | Anna         | 2019-01-07   | 150         |
| 8           | Maria        | 2019-01-08   | 80          |
| 9           | Jaze         | 2019-01-09   | 110         | 
| 1           | Jhon         | 2019-01-10   | 130         | 
| 3           | Jade         | 2019-01-10   | 150         | 
+-------------+--------------+--------------+-------------+
输出:
+--------------+--------------+----------------+
| visited_on   | amount       | average_amount |
+--------------+--------------+----------------+
| 2019-01-07   | 860          | 122.86         |
| 2019-01-08   | 840          | 120            |
| 2019-01-09   | 840          | 120            |
| 2019-01-10   | 1000         | 142.86         |
+--------------+--------------+----------------+
解释:
第一个七天消费平均值从 2019-01-01 到 2019-01-07 是restaurant-growth/restaurant-growth/ (100 + 110 + 120 + 130 + 110 + 140 + 150)/7 = 122.86
第二个七天消费平均值从 2019-01-02 到 2019-01-08 是 (110 + 120 + 130 + 110 + 140 + 150 + 80)/7 = 120
第三个七天消费平均值从 2019-01-03 到 2019-01-09 是 (120 + 130 + 110 + 140 + 150 + 80 + 110)/7 = 120
第四个七天消费平均值从 2019-01-04 到 2019-01-10 是 (130 + 110 + 140 + 150 + 80 + 110 + 130 + 150)/7 = 142.86

这道题的难点在于我们如何基于当天拿到前6天的数据,以来求取这七天的平均数。

而且拿到了这样的数据我们还得想怎么去除不满足前面有6天的数据,例如示例的2019-01-01,它前面都没有六天的数据,所以就没有必要展示。

我们知道一定的是基于七天的一个度量去进行计算,所以我们可以联想到一个窗口,窗口的大小固定为7,基于当天我们这个窗口包含住前6天的数据进行计算来得到结果。

我们知道MySQL是有窗口函数的,但是其实窗口函数是有定长的窗口的功能。

语法为:

sql 复制代码
<window_function> OVER (
  [PARTITION BY partition_column]
  [ORDER BY order_column]
  [ROWS or RANGE BETWEEN <frame_start> AND <frame_end>]
)

后面的ROWS与RANGE就是用来制定窗口的大小的。

详情可以查看我上一篇定长窗口的SQL

https://blog.csdn.net/m0_65013257/article/details/142170042?spm=1001.2014.3001.5501

现在我们已经有了计算固定窗口大小的函数,但我们还得需要一个细节。每一天是有多条记录的,也就是会有多个顾客购买,我们应该是基于当天的总额来进行窗口的计算。所以我们首先得算出每一天的总额

sql 复制代码
select visited_on,sum(amount) amount
from customer
group by visited_on

现在我们可以基于这样一个基础表进行计算。需要运用两次窗口函数。

一次窗口计算七天内的总和。一次窗口计算七天内的平均数。

写出对应的SQL

sql 复制代码
select visited_on,
sum(amount) over (order by visited_on rows 6 preceding) amount,
avg(t1.amount) over (order by visited_on rows 6 preceding) as average_amount
from (
    select visited_on,sum(amount) amount
    from customer
    group by visited_on
) t1

这里还有一点瑕疵,平均数题目的示例中需要保留两位小数。所以我们还要使用Round函数

sql 复制代码
select visited_on,
sum(amount) over (order by visited_on rows 6 preceding) amount,
round(avg(t1.amount) over (order by visited_on rows 6 preceding),2) as average_amount
from (
    select visited_on,sum(amount) amount
    from customer
    group by visited_on
) t1

现在我们就算出每一天的七天内的平均额度与总额度了。但是我们还得需要去除未能有前面6天数据的数据。那这样我们应该有两种想法。一种应该是跳过,还有一种应该是基于一种判定,我们只需要判定后的数据。

我这里先阐述跳过的方法。我们可以跳过前六天的数据,然后获取后面所有的数据即可,但是遇到一个麻烦的事,MySQL当中没有这样的语法说获取到后面所有的数据。但我们可以拟一个较大的数,这样就可以满足我们的需求。

完整的SQL如下

sql 复制代码
select visited_on,
sum(amount) over (order by visited_on rows 6 preceding) amount,
round(avg(t1.amount) over (order by visited_on rows 6 preceding),2) as average_amount
from (
    select visited_on,sum(amount) amount
    from customer
    group by visited_on
) t1
limit 100000000000000 offset 6

那我们如何基于第二种想法解题呢,或者说还有其他方法吗?

实际上我们可以减少一次窗口函数的使用,因为有了七天的总额度,我们可以直接除以7就可以得倒平均数。而除去前六天的数据可以已时间的差值来进行判定,拿到所有时间中的最小值,然后当天的时间剪去最小值的时间如果大于等于6就行。

我们基础表不变,还是需要每一天的总额。

sql 复制代码
select visited_on,sum(amount) amount
        from customer
        group by visited_on
        ) t1

然后运用一次窗口计算总额

sql 复制代码
select visited_on,
    sum(amount) over (order by visited_on rows 6 preceding) amount
    from (
        select visited_on,sum(amount) amount
        from customer
        group by visited_on
        ) t1

然后筛选时间的SQL语句为

sql 复制代码
where datediff(visited_on,(select min(visited_on) from customer)) >= 6

然后算出平均数即可。总SQL为

sql 复制代码
select visited_on,
amount,
round(amount / 7,2) as average_amount
from
(
    select visited_on,
    sum(amount) over (order by visited_on rows 6 preceding) amount
    from (
        select visited_on,sum(amount) amount
        from customer
        group by visited_on
        ) t1
) t2
where datediff(visited_on,(select min(visited_on) from customer)) >= 6
相关推荐
圣保罗的大教堂38 分钟前
leetcode 61. 旋转链表 中等
leetcode
我爱cope2 小时前
【Agent智能体4 | 智能体AI的应用】
数据库·人工智能·职场和发展
知识分享小能手3 小时前
Flask入门学习教程,从入门到精通,数据库操作 — 知识点详解与案例代码(4)
数据库·学习·flask
我是一颗柠檬3 小时前
【MySQL全面教学】MySQL基础SQL语句Day3(2026年)
数据库·后端·sql·mysql·oracle
XS0301063 小时前
MyBatis动态SQL
数据库·sql·mybatis
MandalaO_O3 小时前
MyBatis 与 MySQL 执行流程
数据库·mysql·mybatis
珊瑚里的鱼4 小时前
leetcode42雨水
算法·leetcode
l1t5 小时前
DeepSeek总结的将 Rust Delta Kernel 集成到 ClickHouse
数据库·clickhouse·rust
qq_283720055 小时前
万字深度:Chroma 向量数据库全解析 — 核心原理、实战操作、性能优化与工程最佳实践
数据库·性能优化
过期动态5 小时前
【LeetCode 热题 100】字母异位分组
java·算法·leetcode·职场和发展·哈希算法