LeetCode_sql_day31(1384.按年度列出销售总额)

news/2024/9/22 16:34:17 标签: sql, 数据库

目录

描述  1384.按年度列出销售总额

数据准备

分析

法一

法二

代码

总结


描述  1384.按年度列出销售总额

 Product 表:

+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| product_id    | int     |
| product_name  | varchar |
+---------------+---------+
product_id 是这张表的主键(具有唯一值的列)。
product_name 是产品的名称。

Sales 表:

+---------------------+---------+
| Column Name         | Type    |
+---------------------+---------+
| product_id          | int     |
| period_start        | date    |
| period_end          | date    |
| average_daily_sales | int     |
+---------------------+---------+
product_id 是这张表的主键(具有唯一值的列)。
period_start 和 period_end 是该产品销售期的起始日期和结束日期,且这两个日期包含在销售期内。
average_daily_sales 列存储销售期内该产品的日平均销售额。
销售日期范围为2018年到2020年。

编写解决方案,找出每个产品每年的总销售额,并包含 product_id , product_name , report_year 以及 total_amount 。

返回结果并按 product_id 和 report_year 排序

返回结果格式如下例所示。

示例 1:

输入:
Product table:
+------------+--------------+
| product_id | product_name |
+------------+--------------+
| 1          | LC Phone     |
| 2          | LC T-Shirt   |
| 3          | LC Keychain  |
+------------+--------------+
Sales table:
+------------+--------------+-------------+---------------------+
| product_id | period_start | period_end  | average_daily_sales |
+------------+--------------+-------------+---------------------+
| 1          | 2019-01-25   | 2019-02-28  | 100                 |
| 2          | 2018-12-01   | 2020-01-01  | 10                  |
| 3          | 2019-12-01   | 2020-01-31  | 1                   |
+------------+--------------+-------------+---------------------+
输出:
+------------+--------------+-------------+--------------+
| product_id | product_name | report_year | total_amount |
+------------+--------------+-------------+--------------+
| 1          | LC Phone     |    2019     | 3500         |
| 2          | LC T-Shirt   |    2018     | 310          |
| 2          | LC T-Shirt   |    2019     | 3650         |
| 2          | LC T-Shirt   |    2020     | 10           |
| 3          | LC Keychain  |    2019     | 31           |
| 3          | LC Keychain  |    2020     | 31           |
+------------+--------------+-------------+--------------+
解释:
LC Phone 在 2019-01-25 至 2019-02-28 期间销售,该产品销售时间总计35天。销售总额 35*100 = 3500。
LC T-shirt 在 2018-12-01 至 2020-01-01 期间销售,该产品在2018年、2019年、2020年的销售时间分别是31天、365天、1天,2018年、2019年、2020年的销售总额分别是31*10=310、365*10=3650、1*10=10。
LC Keychain 在 2019-12-01 至 2020-01-31 期间销售,该产品在2019年、2020年的销售时间分别是:31天、31天,2019年、2020年的销售总额分别是31*1=31、31*1=31。

数据准备

sql">Create table If Not Exists Product (product_id int, product_name varchar(30))
Create table If Not Exists Sales (product_id int, period_start date, period_end date, average_daily_sales int)
Truncate table Product
insert into Product (product_id, product_name) values ('1', 'LC Phone ')
insert into Product (product_id, product_name) values ('2', 'LC T-Shirt')
insert into Product (product_id, product_name) values ('3', 'LC Keychain')
Truncate table Sales
insert into Sales (product_id, period_start, period_end, average_daily_sales) values ('1', '2019-01-25', '2019-02-28', '100')
insert into Sales (product_id, period_start, period_end, average_daily_sales) values ('2', '2018-12-01', '2020-01-01', '10')
insert into Sales (product_id, period_start, period_end, average_daily_sales) values ('3', '2019-12-01', '2020-01-31', '1')

分析

法一

①首先用recursive循环构造出这个report_year 我是用period_start来构造 计数器是 开始年份加一 停止条件是结束年份不大于开始年份就停止 

with recursive year as (select product_id,
                               cast(year(period_start) as char) report_year,
                               year(period_end)                 end,
                               average_daily_sales,
                               period_start,
                               period_end
                        from Sales
                        union all
                        select product_id, report_year + 1, end, average_daily_sales, period_start, period_end
                        from year
                        where end > report_year)
select * from year

②使用case when条件判断 每个产品在该年的销售天数

如果report_year 与开始和结束的时间年份相同 说明 该产品只在当年销售 用结束时间减去开始时间 + 1 即可

如果report_year与开始时间年份相同 小于结束时间的年份 说明该产品在下一年还在销售 此时用concat(开始时间年份,‘-12-31’) 当年最后一天的时间减去开始销售的时间 作为该年销售天数

如果report_year不等于开始时间年份 也不等于结束时间年份 说明该产品该年一整年都在销售 返回365

如果report_year大于开始时间年份 等于结束时间年份 说明 在该年销售结束 用该年结束时间减去构造的concat(结束时间年份,'-01-01') +1 即该年销售天数

select product_id,
                report_year,
                average_daily_sales,
                case
                    when report_year = year(period_start) and report_year = year(period_end)
                        then datediff(period_end, period_start) + 1 -- 产品只在当年卖
                    when report_year = year(period_start) and report_year < year(period_end)
                        then datediff(concat(report_year, '-12-31'), period_start) + 1 -- 产品销售年份与产品开始销售年份相同时
                    when report_year > year(period_start) and report_year < year(period_end)
                        then 365 -- 产品销售年份 跨越了多个年份
                    when report_year > year(period_start) and report_year = year(period_end) -- 产品销售年份与产品结束销售年份相同时
                        then datediff(period_end, concat(report_year, '-01-01')) + 1
                    end r1
         from year

③最后按照题目要求求出总销售额,连接产品名称 并且排序

select t2.product_id, product_name, report_year, r1 * average_daily_sales total_amount
from t2
         join product on t2.product_id = product.product_id
order by product_id, report_year

 # 用cast强制转换report_year 年 是因为题目最后要求使用字符串类型

法二

①利用recursive求出最大的Sales表中的时间差

with recursive diff as (select 0 as day_diff
                        union all
                        select day_diff + 1
                        from diff
                        where day_diff < (select max(datediff(period_end, period_start)) from Sales))
select * from diff

② 用开始销售的日期加上日期差就是销售的年份 这里很巧妙的将diff循环表与Sales表连接起来 相当于标明了每一天的销售年份

with recursive diff as (select 0 as day_diff
                        union all
                        select day_diff + 1
                        from diff
                        where day_diff < (select max(datediff(period_end, period_start)) from Sales))
select sales.product_id,
       cast(year(date_add(period_start, interval day_diff day)) as char) as report_year, 
day_diff
from diff
         join sales on datediff(period_end, period_start) >= day_diff

③此时就可以根据产品,年份 计算该年总的销售额  同时连接产品名称 排序 cast强制转换year的类型为字符串型 原因同上

select sales.product_id,
       product_name,
       cast(year(date_add(period_start, interval day_diff day)) as char) as report_year,
       sum(average_daily_sales)
       total_amount
#         day_diff
from diff
         join sales on datediff(period_end, period_start) >= day_diff
         join product on Sales.product_id = Product.product_id
group by product_id,
         product_name,
         report_year
order by product_id, report_year

代码

sql"># 法一:
with recursive year as (select product_id,
                               cast(year(period_start) as char) report_year,
                               year(period_end)                 end,
                               average_daily_sales,
                               period_start,
                               period_end
                        from Sales
                        union all
                        select product_id, report_year + 1, end, average_daily_sales, period_start, period_end
                        from year
                        where end > report_year)

   , t2 as (select product_id,
                   report_year,
                   average_daily_sales,
                   case
                       when report_year = year(period_start) and report_year = year(period_end)
                           then datediff(period_end, period_start) + 1 -- 产品只在当年卖
                       when report_year = year(period_start) and report_year < year(period_end)
                           then datediff(concat(report_year, '-12-31'), period_start) + 1 -- 产品销售年份与产品开始销售年份相同时
                       when report_year > year(period_start) and report_year < year(period_end)
                           then 365 -- 产品销售年份 跨越了多个年份
                       when report_year > year(period_start) and report_year = year(period_end) -- 产品销售年份与产品结束销售年份相同时
                           then datediff(period_end, concat(report_year, '-01-01')) + 1
                       end r1
            from year)
select t2.product_id, product_name, report_year, r1 * average_daily_sales total_amount
from t2
         join product on t2.product_id = product.product_id
order by product_id, report_year;
# 法二:
with recursive diff as (select 0 as day_diff
                        union all
                        select day_diff + 1
                        from diff
                        where day_diff < (select max(datediff(period_end, period_start)) from Sales))
select sales.product_id,
       product_name,
       cast(year(date_add(period_start, interval day_diff day)) as char) as report_year,
       sum(average_daily_sales)                                             total_amount
#        day_diff
from diff
         join sales on datediff(period_end, period_start) >= day_diff
         join product on Sales.product_id = Product.product_id
group by product_id, product_name, report_year
order by product_id, report_year;

总结

①加深对recursive循环的理解

②对于法二所展现的思想 需要积累

先求出最大的时间差 然后用开始时间相加 获取每一天的年份  省去了复杂的条件判断


http://www.niftyadmin.cn/n/5670581.html

相关文章

计算机毕业设计 基于 Hadoop平台的岗位推荐系统 SpringBoot+Vue 前后端分离 附源码 讲解 文档

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

深度学习02-pytorch-06-张量的形状操作

在 PyTorch 中&#xff0c;张量的形状操作是非常重要的&#xff0c;可以让你灵活地调整和处理张量的维度和数据结构。以下是一些常用的张量形状函数及其用法&#xff0c;带有详细解释和举例说明&#xff1a; 1. reshape() 功能: 改变张量的形状&#xff0c;但不改变数据的顺序…

2.《DevOps》系列K8S部署CICD流水线之部署NFS网络存储与K8S创建StorageClass

架构 服务器IP服务名称硬件配置192.168.1.100k8s-master8核、16G、120G192.168.1.101k8s-node18核、16G、120G192.168.1.102k8s-node28核、16G、120G192.168.1.103nfs2核、4G、500G操作系统:Rocky9.3 后续通过K8S部署GitLab、Harbor、Jenkins 一、环境准备 #关闭防火墙开机自…

【Delphi】通过 LiveBindings Designer 链接控件示例

本教程展示了如何使用 LiveBindings Designer 可视化地创建控件之间的 LiveBindings&#xff0c;以便创建只需很少或无需源代码的应用程序。 在本教程中&#xff0c;您将创建一个高清多设备应用程序&#xff0c;该应用程序使用 LiveBindings 绑定多个对象&#xff0c;以更改圆…

Spring Mybatis 动态语句 总结

1.简介 Mybatis 提供动态语句的功能来增强多条件变动的查询语句。 2.代码 if和where搭配使用&#xff1a; <select id"query" resultType"a">select * from t_a<where><!-- where内没有条件满足&#xff0c;不转成where&#xff0c;有…

【LLM学习之路】9月16日 第六天

【LLM学习之路】9月16日 第六天 损失函数 L1Loss 可以取平均也可以求和 参数解析 input &#xff08;N&#xff0c;*&#xff09; N是batchsize&#xff0c;星号代表可以是任意维度 不是输入的参数&#xff0c;只是描述数据 target 形状要同上 MSELoss平方差 CrossEntr…

C#测试调用PdfiumViewer浏览PDF文件的基本用法

印章管理项目后续准备实现打开浏览PDF文件并进行盖章的功能&#xff0c;需要在Winform中使用控件在线浏览PDF文件&#xff0c;在网上找了几个开源的PDF浏览控件进行测试&#xff0c;以便应用于印章管理项目。本文测试调用PdfiumViewer模块打开及浏览PDF文件。   PdfiumViewer…

Redis 缓存雪崩、缓存穿透、缓存击穿详解

缓存雪崩 缓存雪崩指的是大量缓存数据在同一时间失效&#xff0c;导致所有请求直接打到数据库或下游系统&#xff0c;造成数据库瞬时压力剧增&#xff0c;甚至可能引发系统崩溃。 形成原因&#xff1a; 缓存数据同时过期&#xff1a;由于缓存过期时间设置不合理&#xff0c;…