【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 代码在数据库中运行,将得到的结果与预期输出进行对比,如果结果一致,则说明我们的代码实现是正确的。

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

相关推荐
马克Markorg4 小时前
常见的向量数据库和具有向量数据库能力的数据库
数据库
Coder_Boy_6 小时前
技术让开发更轻松的底层矛盾
java·大数据·数据库·人工智能·深度学习
helloworldandy6 小时前
使用Pandas进行数据分析:从数据清洗到可视化
jvm·数据库·python
数据知道8 小时前
PostgreSQL 故障排查:如何找出数据库中最耗时的 SQL 语句
数据库·sql·postgresql
qq_12498707538 小时前
基于SSM的动物保护系统的设计与实现(源码+论文+部署+安装)
java·数据库·spring boot·毕业设计·ssm·计算机毕业设计
枷锁—sha8 小时前
【SRC】SQL注入WAF 绕过应对策略(二)
网络·数据库·python·sql·安全·网络安全
Coder_Boy_8 小时前
基于SpringAI的在线考试系统-考试系统开发流程案例
java·数据库·人工智能·spring boot·后端
Gain_chance8 小时前
35-学习笔记尚硅谷数仓搭建-DWS层最近n日汇总表及历史至今汇总表建表语句
数据库·数据仓库·hive·笔记·学习
此生只爱蛋8 小时前
【Redis】主从复制
数据库·redis
马猴烧酒.9 小时前
【面试八股|JAVA多线程】JAVA多线程常考面试题详解
java·服务器·数据库