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

目录

描述  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。

数据准备

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_endfrom Salesunion allselect product_id, report_year + 1, end, average_daily_sales, period_start, period_endfrom yearwhere 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,casewhen 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')) + 1end r1from year

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

select t2.product_id, product_name, report_year, r1 * average_daily_sales total_amount
from t2join 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_diffunion allselect day_diff + 1from diffwhere day_diff < (select max(datediff(period_end, period_start)) from Sales))
select * from diff

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

with recursive diff as (select 0 as day_diffunion allselect day_diff + 1from diffwhere 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 diffjoin 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 diffjoin sales on datediff(period_end, period_start) >= day_diffjoin product on Sales.product_id = Product.product_id
group by product_id,product_name,report_year
order by product_id, report_year

代码

# 法一:
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_endfrom Salesunion allselect product_id, report_year + 1, end, average_daily_sales, period_start, period_endfrom yearwhere end > report_year), t2 as (select product_id,report_year,average_daily_sales,casewhen 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')) + 1end r1from year)
select t2.product_id, product_name, report_year, r1 * average_daily_sales total_amount
from t2join product on t2.product_id = product.product_id
order by product_id, report_year;
# 法二:
with recursive diff as (select 0 as day_diffunion allselect day_diff + 1from diffwhere 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 diffjoin sales on datediff(period_end, period_start) >= day_diffjoin 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.xdnf.cn/news/147581.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

CentOS Stream 9部署docker,并开启API

1、安装docker &#xff08;1&#xff09;安装Docker的依赖项和存储库 sudo dnf install -y dnf-plugins-core sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo &#xff08;2&#xff09;安装Docker sudo dnf install -y docke…

网站建设中,网站设计的未来发展趋势是什么

网站建设中&#xff0c;网站设计的未来发展趋势是多方面的&#xff0c;涵盖了技术革新、用户体验优化以及市场需求变化等多个维度。以下是对网站设计未来发展趋势的详细预测&#xff1a; 移动优先与响应式设计&#xff1a;随着移动设备的普及&#xff0c;未来的网站设计将更加注…

从零开始:在VSCode中打造完美的C++开发环境

在现代软件开发中&#xff0c;选择一个合适的集成开发环境 (IDE) 至关重要&#xff0c;它不仅能够提高工作效率&#xff0c;还能让编程变得更加轻松愉快。VSCode 凭借其轻量化、高度扩展性以及强大的插件生态&#xff0c;已成为众多开发者的首选。然而&#xff0c;要在 VSCode …

[Redis][Set]详细讲解

目录 0.前言1.常用命令1.SADD2.SMEMBERS3.SISMEMBER4.SCARD5.SPOP6.SMOVE7.SREM 2.集合间操作0.是什么&#xff1f;1.SINTER2.SINTERSTORE3.SUNION4.SUNIONSTORE5.SDIFF6.SDIFFSTORE 3.内部编码1.intset(整数集合)2.hashtable(哈希表) 4.使用场景 0.前言 集合类型也是保存多个字…

ReKep——李飞飞团队提出的让机器人具备空间智能:基于视觉语言模型GPT-4o和关系关键点约束

前言 由于工厂、车厂的任务需求场景非常明确&#xff0c;加之自今年年初以来&#xff0c;我司在机器人这个方向的持续大力度投入(包括南京、长沙两地机器人开发团队的先后组建)&#xff0c;使得近期我司七月接到了不少来自车厂/工厂的订单&#xff0c;比如其中的三个例子&…

数据结构与算法-18算法专向(hash)

话题引入&#xff1a; 给你N&#xff08;1<N<10&#xff09;个自然数,每个数的范围为&#xff08;1~10000000000&#xff09;。现在让你以最快的速度判断某一个数是否在这N个数内&#xff0c;不得使用已经封装好的类&#xff0c;该如何实现。 A[] new int[N1]&#xff…

芝士AI一次过!开题报告通用模板,可直接套用!

在正式写开题报告之前&#xff0c;需要搞清楚以下几个问题。 ①你选择这个论文选题的理由是什么&#xff1f;&#xff08;选题背景&#xff09; ②你打算去研究什么&#xff1f;解决什么问题&#xff1f;&#xff08;研究内容&#xff09; ③该选题目前有哪些研究&#xff0…

新峰商城之订单(二):订单生成

在订单确认页面处理完毕后&#xff0c;此时用户单击“提交订单”按钮&#xff0c;商城系统就对应生成一笔订单数据并保存在数据库中&#xff0c;此即订单生成功能。 在单击“提交订单”按钮后&#xff0c;后端会进行一系列操作&#xff0c;包括数据查询、数据判断、数据整合等&…

构建与优化自定义进程池

1. 什么是进程池&#xff1f; 简单来说&#xff0c;进程池就是预先创建固定数量的工作进程&#xff0c;通过设计任务队列或调度算法来分配任务给空闲的进程 —— 实现“负载均衡”。 2. 进程池框架设计 枚举错误返回值&#xff1a; enum {UsageError 1,ArgError,PipeError };…

人工智能时代的学与教

疫情逐渐散去之后&#xff0c;最最吸引全球目光的应该就是ChatGPT-3了。美国政治家亨利基辛格领衔出版的新书《AI世代与我们人类的未来》(The Age of AI and Our Human Future)中举了一个例子来说明ChatGPT-3的能力。首先让ChatGPT-3阅读关于它自身能力的哲学评论之后&#xff…

【吊打面试官系列-MySQL面试题】MyISAM 表格将在哪里存储,并且还提供其存储格式?

大家好&#xff0c;我是锋哥。今天分享关于【MyISAM 表格将在哪里存储&#xff0c;并且还提供其存储格式&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; MyISAM 表格将在哪里存储&#xff0c;并且还提供其存储格式&#xff1f; 每个 MyISAM 表格以三种格式存储…

240912-设置WSL中的Ollama可在局域网访问

A. 最终效果 B. 设置Ollama&#xff08;前提&#xff09; sudo vim /etc/systemd/system/ollama.service[Unit] DescriptionOllama Service Afternetwork-online.target[Service] ExecStart/usr/bin/ollama serve Userollama Groupollama Restartalways RestartSec3 Environme…

读取t x t文件生成exce

读取t x t文件生成excel package com.moka.api.custom.core.controller; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermode…

LangChain基础知识大全

LangChain基础知识大全 一、部署ChatGLM-6B1.拉取源码2.安装环境3.下载模型4.修改api.py配置5.运行api.py 二、Models组件1.LLM&#xff08;大语言模型&#xff09;2.Chat Model&#xff08;聊天模型&#xff09;3.Embedding Model&#xff08;嵌入模型&#xff09;3.1 下载中文…

基于Python的自然语言处理系列(16):TorchText + CNN + Teacher Forcing

在本篇文章中&#xff0c;我们将实现 卷积序列到序列学习模型&#xff08;Convolutional Sequence to Sequence Learning&#xff09;。与之前介绍的基于循环神经网络&#xff08;RNN&#xff09;的模型不同&#xff0c;卷积模型不依赖递归成分&#xff0c;而是通过卷积层&…

增强现实系列—Map-Relative Pose Regression for Visual Re-Localization

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

基于JAVA+SpringBoot+Vue的社区智慧养老监护管理平台

基于JAVASpringBootVue的社区智慧养老监护管理平台 前言 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN[新星计划]导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末附源码下载链接&#x1…

科研绘图系列:R语言多个AUC曲线图(multiple AUC curves)

文章目录 介绍加载R包导入数据数据预处理画图输出结果组图系统信息介绍 多个ROC曲线在同一张图上可以直观地展示和比较不同模型或方法的性能。这种图通常被称为ROC曲线图,它通过比较不同模型的ROC曲线下的面积(AUC)大小来比较模型的优劣。AUC值越大,模型的诊断或预测效果越…

前后端跨域问题及其在ThinkPHP中的解决方案

在现代Web开发中&#xff0c;前后端分离的架构越来越普遍&#xff0c;但这也带来了跨域问题。跨域指的是在一个域下的网页试图请求另一个域的资源&#xff0c;浏览器出于安全考虑会限制这种行为。本文将探讨如何在ThinkPHP中解决跨域问题。 #### 1. 什么是跨域&#xff1f; 跨…

一个皮肤科医生长痘的的自救

内服 复方锌铁钙口服液 丹参瞳胶囊 盐酸米诺环素胶囊 (每天一次) 内服 外用: 克林霉素甲硝搽剂 (泛红的痘痘) 人表皮生长因子(痘印)氢醌软膏 (点阵激光留下的色沉 早晚一次) 至少用两个月【痤疮|痘痘用药 一个皮肤科医生的自救】https://www.bilibili.com/video/BV1zu41…