查询每个产品每年总销售额

题目

  已知有表如下,记录了每个产品id、产品名称、产品销售开始日期、产品销售结束日期以及产品日均销售金额,请计算出每个产品每年的销售金额
在这里插入图片描述
期望结果
在这里插入图片描述
说明

  1. LC Phone 在 2019-01-25 至 2019-02-28 期间销售,该产品销售时间总计35天。销售总额 35*100 = 3500。
  2. LC T-shirt 在 2018-12-01 至 2020-01-01 期间销售,该产品在2018年、2019年、2020年的销售时间分别是31天、365天、1天,2018年、2019年、2020年的销售总额分别是3110=310、36510=3650、1*10=10。
  3. LC Keychain 在 2019-12-01 至 2020-01-31 期间销售,该产品在2019年、2020年的销售时间分别是:31天、31天,2019年、2020年的销售总额分别是311=31、311=31。

   分析:题目中给出的是每个产品的开始时间和结束时间,这里最关键的问题在于一个时间段可能跨年,并且不知道跨几年。所以我们先构建一个年份维表,利用年度维表去切割源每个产品的销售时间。

1构造年度维表

  如下图所示,由于题目中只有3年,所以我们暂先构造3年的年度维表,包含由于题目中只有3年,所以我们暂先构造3年的年度维表。
在这里插入图片描述

2 将原始数据与维表关联

  把原始数据与年份维表进行笛卡尔积,得到每年与原始数据的一个交叉值.
在这里插入图片描述

3 日期交叉的切割分析

  上个步骤发生了笛卡尔积,每个产品都会与年度维表的每一年做关联,我们分别取每个产品与每个年度的交集,如果没有产生交集的年度就过滤,这样即可切割出每个产品的每年售卖的时间段
  如图1所示,下面为产品为“LC Phone”在2019年与维度表关联的情况,因为产品为“LC Phone”只有在2019年有销量,所以与年度维表在时间上取交集后就是“LC Phone”的售卖时间端

](https://i-blog.csdnimg.cn/direct/4e0699ac9a6c4480acef53044ead11e1.png)

图1

  2018年“LC Phone”没有销售,我们来分析一下怎么将2018年的记录过滤掉
  如图2所示,由于该产品在2018年没有被售卖,取period_end和year_end_day的较大值,所以这里取的是period_start的值为2019-01-25作为开始日期,取period_end和year_end_day的较小值,所以这里取的是period_end的值为2018-12-31作为结束日期,这里结束日期小于开始日期,这样就可以将行记录过滤掉,也符合实际没有交集的事实,该产品在2020年与年度维表的交集同样没有交集,也需要被过滤掉。
在这里插入图片描述
图2

  接下来我们分析下’LC T-Shirt’产品的情况,如图3所以,2018年取到的交集是开始时间为2018-12-01,结束时间时2018-12-31
在这里插入图片描述

图3

  同理,'LC T-Shirt’产品在2019年的交集如图4所示,取到的交集是开始时间为2019-01-01,结束时间时2019-12-31
在这里插入图片描述

图4

  同理,'LC T-Shirt’产品在2019年的交集如图5所示,取到的交集是开始时间为2020-01-01,结束时间时2020-01-01
在这里插入图片描述
图5

   以上分析了产品分别与年度维表的每年交集的所有情况,接下来,我们将结束日期小于开始日期的记录过滤掉,就可以得到每个产品每年的售卖时间天数

4 比较计算每年每个产品在售天数

with t_product_sales as (
select 1 as product_id, 'LC Phone' as product_name, '2019-01-25 00:00:00' as period_start, '2019-02-28 00:00:00' as period_end, 100 as average_daily_sales union all
select 2 as product_id, 'LC T-Shirt' as product_name, '2018-12-01 00:00:00' as period_start, '2020-01-01 00:00:00' as period_end, 10 as average_daily_sales union all
select 3 as product_id, 'LC Keychain' as product_name, '2019-12-01 00:00:00' as period_start, '2020-01-31 00:00:00' as period_end, 1 as average_daily_sales
),
dim_year as (
select '2018' as year, '2018-01-01' as year_first_day, '2018-12-31' as year_end_day union all
select '2019' as year, '2019-01-01' as year_first_day, '2019-12-31' as year_end_day union all
select '2020' as year, '2020-01-01' as year_first_day, '2020-12-31' as year_end_day
),
 tmp as (
select product_id,
    product_name,
    period_start,
    period_end,
    average_daily_sales,
    year,
    year_first_day,
    year_end_day,
    datediff(
        if(to_date(period_end) > to_date(year_end_day), to_date(year_end_day), to_date(period_end)),
        if(to_date(period_start) > to_date(year_first_day), to_date(period_start),
            to_date(year_first_day))) as date_diff
from t_product_sales
left join dim_year)
select product_id,
       product_name,
       year,
       date_diff
from tmp
where date_diff >= 0

在这里插入图片描述

5 筛选符合条件数据,计算最终结果

with t_product_sales as (
select 1 as product_id, 'LC Phone' as product_name, '2019-01-25 00:00:00' as period_start, '2019-02-28 00:00:00' as period_end, 100 as average_daily_sales union all
select 2 as product_id, 'LC T-Shirt' as product_name, '2018-12-01 00:00:00' as period_start, '2020-01-01 00:00:00' as period_end, 10 as average_daily_sales union all
select 3 as product_id, 'LC Keychain' as product_name, '2019-12-01 00:00:00' as period_start, '2020-01-31 00:00:00' as period_end, 1 as average_daily_sales
),
dim_year as (
select '2018' as year, '2018-01-01' as year_first_day, '2018-12-31' as year_end_day union all
select '2019' as year, '2019-01-01' as year_first_day, '2019-12-31' as year_end_day union all
select '2020' as year, '2020-01-01' as year_first_day, '2020-12-31' as year_end_day
),
 tmp as (
select product_id,
    product_name,
    period_start,
    period_end,
    average_daily_sales,
    year,
    year_first_day,
    year_end_day,
    datediff(
        if(to_date(period_end) > to_date(year_end_day), to_date(year_end_day), to_date(period_end)),
        if(to_date(period_start) > to_date(year_first_day), to_date(period_start),
            to_date(year_first_day))) as date_diff
from t_product_sales
left join dim_year)
select product_id,
       product_name,
       year,
       (date_diff + 1) * average_daily_sales as total_amount 
from tmp
where date_diff >= 0

在这里插入图片描述

  • 17
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这是一个比较复杂的问题,需要使用Python和数据库操作,以及Echarts绘图库。下面是一个简单的实现步骤: 1. 连接数据库,读取goods表中的date和totalprice列数据。 2. 将date列数据转换成季度信息,可以使用datetime库中的strptime和strftime函数。 3. 将每个季度的totalprice数据进行累加,生成每年每个季度的销售额数据。 4. 将每年的数据按照季度进行分组,生成两年的数据,每两个柱为一组。 5. 使用Echarts绘制柱状图,x轴为季度,y轴为销售额,每两个柱为一组。 下面是一个简单的代码实现,假设使用MySQL数据库和Python的pymysql库: ```python import pymysql import datetime import json # 连接数据库 conn = pymysql.connect(host='localhost', port=3306, user='root', password='123456', db='test') cursor = conn.cursor() # 读取数据 cursor.execute("SELECT date,totalprice FROM goods") rows = cursor.fetchall() # 处理数据 data = {} for row in rows: date = datetime.datetime.strptime(row[0], '%Y/%m') quarter = (date.month - 1) // 3 + 1 year = date.year if year not in data: data[year] = {} if quarter not in data[year]: data[year][quarter] = 0 data[year][quarter] += row[1] # 生成echarts数据 echarts_data = [] for year in range(2021, 2023): for quarter in range(1, 5): echarts_data.append({ "name": "{}Q{}".format(year, quarter), "value": data[year][quarter] if year in data and quarter in data[year] else 0 }) # 绘制echarts柱状图 option = { "xAxis": {"type": "category", "data": ["2021Q1", "2021Q2", "2021Q3", "2021Q4", "2022Q1", "2022Q2", "2022Q3", "2022Q4"]}, "yAxis": {"type": "value"}, "series": [ {"name": "销售额", "type": "bar", "data": echarts_data[0:4]}, {"name": "销售额", "type": "bar", "data": echarts_data[4:8]} ] } print(json.dumps(option)) ``` 这个代码使用了pymysql库连接MySQL数据库,并读取了goods表的date和totalprice列数据。然后使用datetime库将date转换成季度信息,并计算出每个季度的销售额。最后生成了echarts柱状图所需的数据,并使用json库将图表配置信息转换成JSON格式输出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值