1384. 按年度列出销售总额

SQL架构

 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 列存储销售期内该产品的日平均销售额。

编写一段 SQL 查询每个产品每年的总销售额,并包含 product_id, product_name 以及 report_year 等信息。

销售年份的日期介于 2018 年到 2020 年之间。你返回的结果需要按 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。


with recursive sales_period AS ( # 递归体声明
    select
        product_id,
        period_start AS d1, 
        if (str_to_date(concat(year(period_start),'-12-31'), '%Y-%m-%d') < period_end,
            str_to_date(concat(year(period_start),'-12-31'), '%Y-%m-%d'), period_end) AS d2
    from Sales
    UNION ALL
        select
            t.product_id,
            DATE_ADD(t.d2, INTERVAL 1 DAY)AS d1,
            if (DATE_ADD(t.d2, INTERVAL 1 YEAR) < period_end,
                DATE_ADD(t.d2, INTERVAL 1 YEAR), period_end) AS d2
        from sales_period AS t
        JOIN Sales USING(product_id)
        where d2 < Sales.period_end
)


select
    CAST(p.product_id AS CHAR) AS product_id,
    p.product_name AS product_name,
    CAST(year(sp.d1) AS CHAR) AS report_year,
    s.average_daily_sales * (datediff(sp.d2, sp.d1) + 1) AS total_amount
from sales_period AS sp
JOIN Product AS p USING(product_id)
JOIN Sales AS s USING(product_id)
where year(sp.d1) BETWEEN 2018 and 2020

# 题目要求按序返回
order by product_id, report_year

with recursive t(n) as (
    select 0
    union all
    select n+1 from t where n<(select max(datediff(period_end, period_start)) from Sales)
)
select
    s.product_id,
    p.product_name,
    DATE_FORMAT(DATE_ADD(s.period_start, INTERVAL t.n DAY), '%Y') as report_year,
    sum(s.average_daily_sales) as total_amount
from Sales s
    join t on datediff(s.period_end, s.period_start)>=t.n
    join Product p on s.product_id=p.product_id
group by 1, 2, 3
order by 1, 3

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值