当前位置:   article > 正文

第 4 题 打折日期交叉问题_max(edt) over(partition by brand order by stt rows

max(edt) over(partition by brand order by stt rows between unbounded precedi

1、题目要求

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

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

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

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

  1. brand stt edt
  2. oppo;2021-06-05;2021-06-09
  3. oppo;2021-06-11;2021-06-21
  4. vivo;2021-06-05;2021-06-15
  5. vivo;2021-06-09;2021-06-21
  6. redmi;2021-06-05;2021-06-21
  7. redmi;2021-06-09;2021-06-15
  8. redmi;2021-06-17;2021-06-26
  9. huawei;2021-06-05;2021-06-26
  10. huawei;2021-06-09;2021-06-15
  11. huawei;2021-06-17;2021-06-21

2、建表和加载数据

  1. create table if not exists test4(
  2. brand string,
  3. stt string,
  4. edt string
  5. )row format delimited fields terminated by ";";
  6. load data local inpath '/opt/test/t4.txt' overwrite into table test4;

3、分析

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

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

  1. redmi 2021-06-05 2021-06-21
  2. redmi 2021-06-09 2021-06-15
  3. redmi 2021-06-17 2021-06-26

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

  1. 比如:第二行 开始时间2021-06-09 那第二行之前的最大结束时间就是2021-06-211 2021-06-22
  2. 第三行 开始时间2021-06-17 那第三行之前的最大结束时间就是2021-06-211 2021-06-22
  3. redmi 2021-06-05 2021-06-21 null
  4. redmi 2021-06-09 2021-06-15 2021-06-22
  5. redmi 2021-06-17 2021-06-26 2021-06-22
  6. 然后我们在当前行的结束时间减去移下来的第四列数据,大于0就是真实的天数,小于零说明被包含了

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

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

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

        结果:

  1. brand stt edt maxedt
  2. huawei 2021-06-05 2021-06-26 NULL
  3. huawei 2021-06-09 2021-06-15 2021-06-26
  4. huawei 2021-06-17 2021-06-21 2021-06-26
  5. oppo 2021-06-05 2021-06-09 NULL
  6. oppo 2021-06-11 2021-06-21 2021-06-09
  7. redmi 2021-06-05 2021-06-21 NULL
  8. redmi 2021-06-09 2021-06-15 2021-06-21
  9. redmi 2021-06-17 2021-06-26 2021-06-21
  10. vivo 2021-06-05 2021-06-15 NULL
  11. vivo 2021-06-09 2021-06-21 2021-06-15

        3)相减

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

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

                比如:

  1. oppo 2021-06-05 2021-06-09 NULL
  2. 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
  1. select
  2. brand,stt,edt,
  3. datediff(edt,if(maxedt is null,stt,if(maxedt>stt,date_add(maxedt,1),stt))) days
  4. from (
  5. select
  6. brand,stt,edt,
  7. max(edt) over(partition by brand order by stt rows between UNBOUNDED PRECEDING and 1 PRECEDING) maxedt
  8. from test4
  9. )t1;

        结果:

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

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

  1. select
  2. brand,
  3. sum(if(days>0,days+1,0)) days
  4. from (
  5. select
  6. brand,stt,edt,
  7. datediff(edt,if(maxedt is null,stt,if(maxedt>stt,date_add(maxedt,1),stt))) days
  8. from (
  9. select
  10. brand,stt,edt,
  11. max(edt) over(partition by brand order by stt rows between UNBOUNDED PRECEDING and 1 PRECEDING) maxedt
  12. from test4
  13. )t1
  14. )t2
  15. group by brand;

        结果:

  1. brand days
  2. huawei 22
  3. oppo 16
  4. redmi 22
  5. vivo 17

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号