SQL面试题:求时间差之和(有重复不计)

吾爱主题 阅读:161 2024-04-05 14:23:50 评论:0

面试某某公司BI岗位的时候,面试题中的一道sql题,咋看一下很简单,写的时候发现自己缺乏总结,没有很快的写出来。

题目如下:

求每个品牌的促销天数

表sale为促销营销表,数据中存在日期重复的情况,例如id为1的end_date为20180905,id为2的start_date为20180903,即id为1和id为2的存在重复的销售日期,求出每个品牌的促销天数(重复不算)

表结果如下:

?
1 2 3 4 5 6 7 8 9 10 11 + ------+-------+------------+------------+ | id | brand | start_date | end_date | + ------+-------+------------+------------+ | 1 | nike | 2018-09-01 | 2018-09-05 | | 2 | nike | 2018-09-03 | 2018-09-06 | | 3 | nike | 2018-09-09 | 2018-09-15 | | 4 | oppo | 2018-08-04 | 2018-08-05 | | 5 | oppo | 2018-08-04 | 2018-08-15 | | 6 | vivo | 2018-08-15 | 2018-08-21 | | 7 | vivo | 2018-09-02 | 2018-09-12 | + ------+-------+------------+------------+

最终结果应为

 

brand all_days
nike 13
oppo 12
vivo 18

 

建表语句

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 -- ---------------------------- -- Table structure for sale -- ---------------------------- DROP TABLE IF EXISTS `sale`; CREATE TABLE `sale` (   `id` int (11) DEFAULT NULL ,   `brand` varchar (255) DEFAULT NULL ,   `start_date` date DEFAULT NULL ,   `end_date` date DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8;   -- ---------------------------- -- Records of sale -- ---------------------------- INSERT INTO `sale` VALUES (1, 'nike' , '2018-09-01' , '2018-09-05' ); INSERT INTO `sale` VALUES (2, 'nike' , '2018-09-03' , '2018-09-06' ); INSERT INTO `sale` VALUES (3, 'nike' , '2018-09-09' , '2018-09-15' ); INSERT INTO `sale` VALUES (4, 'oppo' , '2018-08-04' , '2018-08-05' ); INSERT INTO `sale` VALUES (5, 'oppo' , '2018-08-04' , '2018-08-15' ); INSERT INTO `sale` VALUES (6, 'vivo' , '2018-08-15' , '2018-08-21' ); INSERT INTO `sale` VALUES (7, 'vivo' , '2018-09-02' , '2018-09-12' );

方式1:

利用自关联下一条记录的方法

?
1 2 3 4 5 6 7 8 9 10 11 select brand, sum (end_date-befor_date+1) all_days from   (   select s.id ,    s.brand ,    s.start_date ,    s.end_date ,    if(s.start_date>=ifnull(t.end_date,s.start_date) ,s.start_date,DATE_ADD(t.end_date,interval 1 day ) ) as befor_date   from sale s left join ( select id+1 as id ,brand,end_date from sale) t on s.id = t.id and s.brand = t.brand   order by s.id   )tmp   group by brand

运行结果

?
1 2 3 4 5 6 7 + -------+---------+ | brand | all_day | + -------+---------+ | nike |  13 | | oppo |  12 | | vivo |  18 | + -------+---------+

该方法对本题中的表格有效,但对于有id不连续的品牌的记录时不一定适用。

方式2:

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 SELECT a.brand, SUM (   CASE    WHEN a.start_date=b.start_date AND a.end_date=b.end_date    AND NOT EXISTS(    SELECT *    FROM sale c LEFT JOIN sale d ON c.brand=d.brand     WHERE d.brand=a.brand     AND c.start_date=a.start_date     AND c.id<>d.id     AND (d.start_date BETWEEN c.start_date AND c.end_date AND d.end_date>c.end_date     OR    c.start_date BETWEEN d.start_date AND d.end_date AND c.end_date>d.end_date)      )     THEN (a.end_date-a.start_date+1)    WHEN (a.id<>b.id AND b.start_date BETWEEN a.start_date AND a.end_date AND b.end_date>a.end_date ) THEN (b.end_date-a.start_date+1)    ELSE 0 END    ) AS all_days FROM sale a JOIN sale b ON a.brand=b.brand GROUP BY a.brand

运行结果

?
1 2 3 4 5 6 7 + -------+----------+ | brand | all_days | + -------+----------+ | nike |  13 | | oppo |  12 | | vivo |  18 | + -------+----------+

其中条件

?
1 2 3 d.start_date BETWEEN c.start_date AND c.end_date AND d.end_date>c.end_date     OR c.start_date BETWEEN d.start_date AND d.end_date AND c.end_date>d.end_date

可以换成

?
1 c.start_date < d.end_date AND (c.end_date > d.start_date)

结果同样正确

用分析函数同样可行的,自己电脑暂时没装oracle,用的mysql写的。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/u012955829/article/details/102754141

可以去百度分享获取分享代码输入这里。
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

【腾讯云】云服务器产品特惠热卖中
搜索
标签列表
    关注我们

    了解等多精彩内容