第 4 题 打折日期交叉问题

Posted NC_NE

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第 4 题 打折日期交叉问题相关的知识,希望对你有一定的参考价值。

1、题目要求

如下为平台商品促销数据: 字段为品牌,打折开始日期,打折结束日期

计算每个品牌总的打折销售天数,注意其中的交叉日期,比如 vivo 品牌,第一次活动时

间为 2021-06-05 到 2021-06-15,第二次活动时间为 2021-06-09 到 2021-06-21 其中 9 号到 15

号为重复天数,只统计一次,即 vivo 总打折天数为 2021-06-05 到 2021-06-21 共计 17 天。

brand     stt       edt
oppo;2021-06-05;2021-06-09
oppo;2021-06-11;2021-06-21
vivo;2021-06-05;2021-06-15
vivo;2021-06-09;2021-06-21
redmi;2021-06-05;2021-06-21
redmi;2021-06-09;2021-06-15
redmi;2021-06-17;2021-06-26
huawei;2021-06-05;2021-06-26
huawei;2021-06-09;2021-06-15
huawei;2021-06-17;2021-06-21

2、建表和加载数据

create table if not exists test4(
brand string,
stt string,
edt string
)row format delimited fields terminated by ";";

load data local inpath '/opt/test/t4.txt' overwrite into table test4;

3、分析

        1)如果没有重复的打折时间,那就直接每次打折结束时间减开始时间加一在聚合求和

但是,如下数据,存在交叉打折的情况

redmi 2021-06-05 2021-06-21
redmi 2021-06-09 2021-06-15
redmi 2021-06-17 2021-06-26

这时我们判断当前行开始时间是不是小于组内之前全部行的最大结束时间,如果小于那就将当前行的开始时间替换成之前行的最大结束时间加1(不加1就重复天了)

比如:第二行 开始时间2021-06-09 那第二行之前的最大结束时间就是2021-06-21 加1 2021-06-22
    第三行 开始时间2021-06-17   那第三行之前的最大结束时间就是2021-06-21 加1 2021-06-22  
redmi 2021-06-05 2021-06-21  null
redmi 2021-06-09 2021-06-15 2021-06-22
redmi 2021-06-17 2021-06-26 2021-06-22

然后我们在当前行的结束时间减去移下来的第四列数据,大于0就是真实的天数,小于零说明被包含了

        到这整个思路就清楚了,下面就是分步骤来实现

        2)将第一行到当前行的最大结束时间移到当前行作为第四列(首先数据都是按照开始时间排好序的,如果没有排好序可以自己先排序)

max(edt) over(partition by brand order by stt rows between UNBOUNDED PRECEDING and 1 PRECEDING) maxedt
select
brand,stt,edt,
max(edt) over(partition by brand order by stt rows between UNBOUNDED PRECEDING and 1 PRECEDING) maxedt
from test4;

        结果:

brand	 stt	        edt	     maxedt
huawei	2021-06-05	2021-06-26	NULL
huawei	2021-06-09	2021-06-15	2021-06-26
huawei	2021-06-17	2021-06-21	2021-06-26
oppo	2021-06-05	2021-06-09	NULL
oppo	2021-06-11	2021-06-21	2021-06-09
redmi	2021-06-05	2021-06-21	NULL
redmi	2021-06-09	2021-06-15	2021-06-21
redmi	2021-06-17	2021-06-26	2021-06-21
vivo	2021-06-05	2021-06-15	NULL
vivo	2021-06-09	2021-06-21	2021-06-15

        3)相减

                1、 第一个if判断maxedt是不是null,如果是null,那就当前行的(edt-stt)

                2、第二个if判断maxedt是不是比stt还小,如果小,那就不存在时间交叉的情况,那也直接(edt-stt) 就好了

                比如:

oppo	2021-06-05	2021-06-09	NULL
oppo	2021-06-11	2021-06-21	2021-06-09

                3、只有都不是上面两种情况下,才是(edt-maxedt+1)

datediff(edt,if(maxedt is null,stt,if(maxedt>stt,date_add(maxedt,1),stt))) days
select
    brand,stt,edt,
    datediff(edt,if(maxedt is null,stt,if(maxedt>stt,date_add(maxedt,1),stt))) days
from (
    select 
        brand,stt,edt,
        max(edt) over(partition by brand order by stt rows between UNBOUNDED PRECEDING and 1 PRECEDING) maxedt
    from test4
)t1;

        结果:

brand	stt	          edt	   days
huawei	2021-06-05	2021-06-26	21
huawei	2021-06-09	2021-06-15	-12
huawei	2021-06-17	2021-06-21	-6
oppo	2021-06-05	2021-06-09	4
oppo	2021-06-11	2021-06-21	10
redmi	2021-06-05	2021-06-21	16
redmi	2021-06-09	2021-06-15	-7
redmi	2021-06-17	2021-06-26	4
vivo	2021-06-05	2021-06-15	10
vivo	2021-06-09	2021-06-21	5

        4)按照品牌分组,计算每条数据加一的总和(加1和第3题相同)

select
brand,
sum(if(days>0,days+1,0)) days
from (
    select
        brand,stt,edt,
        datediff(edt,if(maxedt is null,stt,if(maxedt>stt,date_add(maxedt,1),stt))) days
    from (
        select 
            brand,stt,edt,
            max(edt) over(partition by brand order by stt rows between UNBOUNDED PRECEDING and 1 PRECEDING) maxedt
        from test4
    )t1
)t2
group by brand;

        结果:

brand	days
huawei	22
oppo	16
redmi	22
vivo	17

以上是关于第 4 题 打折日期交叉问题的主要内容,如果未能解决你的问题,请参考以下文章

仅需6道题轻松掌握Python时间和日期处理 | Python技能树征题

如何优化C ++代码的以下片段 - 卷中的零交叉

第2题——DNA片段

第十四届蓝桥杯三月真题刷题训练——第 8 天

Python练习册 第 0013 题: 用 Python 写一个爬图片的程序,爬 这个链接里的日本妹子图片 :-),(http://tieba.baidu.com/p/2166231880)(代码片段

Go语言入门150题 L1-051 打折 (5 分) Go语言|Golang