各位用户为了找寻关于SQL面试题:求时间差之和(有重复不计)的资料费劲了很多周折。这里教程网为您整理了关于SQL面试题:求时间差之和(有重复不计)的相关资料,仅供查阅,以下为您介绍关于SQL面试题:求时间差之和(有重复不计)的详细内容
面试某某公司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 |
+
------+-------+------------+------------+
最终结果应为
建表语句
? 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 11select
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 18SELECT
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 3d.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
可以换成
? 1c.start_date < d.end_date
AND
(c.end_date > d.start_date)
结果同样正确
用分析函数同样可行的,自己电脑暂时没装oracle,用的mysql写的。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
原文链接:https://blog.csdn.net/u012955829/article/details/102754141