【LeetCode 题解】数据库:1321.餐馆营业额变化增长

一、问题描述

本题给定了一个名为 Customer 的表,记录了餐馆顾客的交易数据,包括顾客 ID、姓名、访问日期和消费金额。作为餐馆老板,我们的任务是分析营业额的变化增长情况,具体来说,就是计算以 7 天(某日期 + 该日期前的 6 天)为一个时间段的顾客消费平均值,并按访问日期升序排序,同时要保留两位小数。

二、表结构分析

Customer 表的结构如下:

列名 类型 说明
customer_id int 顾客的唯一标识,用于区分不同的顾客。
name varchar 顾客的姓名。
visited_on date 顾客访问餐馆的日期,与 customer_id 一起构成表的主键,确保每一条记录的唯一性。
amount int 顾客在当天的消费总额。

三、解题思路

  1. 确定时间段:要计算以 7 天为一个时间段的消费情况,我们需要对每个日期,找到其前 6 天以及当天的所有消费记录。

  2. 计算消费总和:对于每个确定的 7 天时间段,计算该时间段内的消费总额。

  3. 计算平均值:根据消费总和,计算出该 7 天时间段的平均消费金额,并保留两位小数。

  4. 结果排序:将计算得到的每个 7 天时间段的访问日期、消费总额和平均消费金额按访问日期升序排列输出。

为了实现以上思路,我们可以使用 SQL 中的窗口函数来简化计算过程,窗口函数可以在不改变表结构的情况下,对数据进行分组和聚合操作。

四、SQL 代码实现

复制代码
-- 选择访问日期、消费总额和平均消费金额
SELECT 
    visited_on,
    amount,
    -- 保留两位小数
    ROUND(amount / 7, 2) AS average_amount
FROM 
    (
        -- 子查询计算每个 7 天时间段的消费总额
        SELECT 
            visited_on,
            SUM(amount) AS amount
        FROM 
            (
                -- 使用窗口函数计算每个日期及其前 6 天的消费总和
                SELECT 
                    visited_on,
                    SUM(amount) OVER (ORDER BY visited_on ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS amount
                FROM 
                    Customer
            ) sub1
        WHERE 
            visited_on >= (SELECT MIN(visited_on) FROM Customer + INTERVAL 6 DAY)
        GROUP BY 
            visited_on
    ) sub2
ORDER BY 
    visited_on;

五、代码详细解释

1、最内层子查询

复制代码
SELECT 
    visited_on,
    SUM(amount) OVER (ORDER BY visited_on ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS amount
FROM 
    Customer

这里使用了窗口函数 SUM(amount) OVER (ORDER BY visited_on ROWS BETWEEN 6 PRECEDING AND CURRENT ROW)OVER 子句指定了窗口的定义,ORDER BY visited_on 表示按照访问日期进行排序,ROWS BETWEEN 6 PRECEDING AND CURRENT ROW 表示窗口的范围是当前行以及其前 6 行。所以这个子查询的作用是计算每个日期及其前 6 天的消费总和,并将结果命名为 amount

2、中间子查询

复制代码
SELECT 
    visited_on,
    SUM(amount) AS amount
FROM 
    (最内层子查询) sub1
WHERE 
    visited_on >= (SELECT MIN(visited_on) FROM Customer + INTERVAL 6 DAY)
GROUP BY 
    visited_on

这个子查询首先从最内层子查询的结果中选择 visited_onamount 列。WHERE 子句用于筛选出访问日期大于等于最早访问日期加上 6 天的记录,因为在最早访问日期加上 6 天之前的日期无法构成完整的 7 天时间段。然后使用 GROUP BY visited_on 对结果按访问日期进行分组,并再次计算每个分组(即每个 7 天时间段)的消费总额,将结果命名为 amount

3、最外层查询

复制代码
SELECT 
    visited_on,
    amount,
    ROUND(amount / 7, 2) AS average_amount
FROM 
    (中间子查询) sub2
ORDER BY 
    visited_on;

最外层查询从中间子查询的结果中选择 visited_onamount 列,并使用 ROUND(amount / 7, 2) 计算平均消费金额,保留两位小数,并将结果命名为 average_amount。最后使用 ORDER BY visited_on 按访问日期升序排列结果。

六、复杂度分析

  1. 时间复杂度 :假设 Customer 表中有 n 条记录。最内层子查询使用窗口函数,对于每一行数据,窗口函数的计算时间复杂度为 (O(1))(因为窗口范围固定为 7 行),所以最内层子查询的时间复杂度为 (O(n))。中间子查询对最内层子查询的结果进行分组和筛选,时间复杂度也为 (O(n))。最外层查询对中间子查询的结果进行简单的选择和排序,排序的时间复杂度为 (O(n log n))。综合来看,总的时间复杂度为 (O(n log n))。

  2. 空间复杂度:在查询过程中,我们没有使用额外的与数据规模相关的空间,只是对表中的数据进行了读取和处理,因此空间复杂度为 (O(1))。

七、测试用例验证

1、输入数据

复制代码
-- 插入示例数据
INSERT INTO Customer (customer_id, name, visited_on, amount) VALUES
(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);

2、预期输出

复制代码
+--------------+--------------+----------------+
| 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         |
+--------------+--------------+----------------+

3、验证过程:将上述 SQL 代码在数据库中运行,将得到的结果与预期输出进行对比,如果结果一致,则说明我们的代码实现是正确的。

感谢各位的阅读,后续将持续给大家讲解力扣中的算法题和数据库题,如果觉得这篇内容对你有帮助,别忘了点赞和关注,后续还有更多精彩的算法解析与你分享!

相关推荐
stormsha几秒前
0x02.Redis 集群的实现原理是什么?
数据库·redis·缓存
独行soc1 分钟前
2025年常见渗透测试面试题- 应急响应(题目+回答)
java·前端·数据库·python·安全·面试·csrf
极限实验室8 分钟前
Easysearch S3 备份实战
数据库
GottdesKrieges22 分钟前
OceanBase企业版单机部署:obd命令行方式
数据库·oceanbase
梭七y26 分钟前
【力扣hot100题】(089)最长有效括号
算法·leetcode·职场和发展
萨达大43 分钟前
软考高级-系统架构设计师 案例题-数据库系统
数据库·oracle·系统架构·软考高级·orm
八股文领域大手子1 小时前
《从单体到分布式:一个订单系统的架构升级》
java·数据库·spring·缓存·mybatis
lilye662 小时前
程序化广告行业(80/89):近年发展动态与技术标准演进
sql·json·rabbitmq
江沉晚呤时2 小时前
深入探析C#设计模式:访问者模式(Visitor Pattern)的原理与应用
java·服务器·开发语言·数据库·.netcore
老大白菜2 小时前
mysql 商城商品属性开发的动态解决方案
数据库·mysql