LeetCode601查询体育馆的人流量问题详解(MySQL三种方法实现)

题目如下:

X 市建了一个新的体育馆,每日人流量信息被记录在这三列信息中:序号 (id)、日期 (date)、 人流量 (people)。

请编写一个查询语句,找出高峰期时段,要求连续三天及以上,并且每天人流量均不少于100。

例如,表 stadium

+------+------------+-----------+
| id   | date       | people    |
+------+------------+-----------+
| 1    | 2017-01-01 | 10        |
| 2    | 2017-01-02 | 109       |
| 3    | 2017-01-03 | 150       |
| 4    | 2017-01-04 | 99        |
| 5    | 2017-01-05 | 145       |
| 6    | 2017-01-06 | 1455      |
| 7    | 2017-01-07 | 199       |
| 8    | 2017-01-08 | 188       |
+------+------------+-----------+

对于上面的示例数据,输出为:

+------+------------+-----------+
| id   | date       | people    |
+------+------------+-----------+
| 5    | 2017-01-05 | 145       |
| 6    | 2017-01-06 | 1455      |
| 7    | 2017-01-07 | 199       |
| 8    | 2017-01-08 | 188       |
+------+------------+-----------+
Note:
每天只有一行记录,日期随着 id 的增加而增加。

方法一:使用自关联。

完整代码:

select distinct s1.* from stadium as s1,stadium as s2,stadium as s3 
where 
((s1.id+1=s2.id and s2.id+1=s3.id) or (s1.id+2=s2.id and s2.id-1=s3.id)
or (s1.id-1=s2.id and s2.id+2=s3.id) or (s1.id+1=s2.id and s2.id-2=s3.id)
or (s1.id-1=s2.id and s2.id-1=s3.id) or (s1.id-2=s2.id and s2.id+1=s3.id))
and
(s1.people>=100 and s2.people>=100 and s3.people>=100) order by s1.id;

解析:

SELECT e.id,e.date,e.people FROM
(SELECT id, s.date,
@sdate1 := 
(CASE
WHEN s.people >=100 THEN @sdate1
ELSE @sdate1 + 1
END) AS sdate,s.people FROM  stadium as s,(SELECT @sdate1 := 0) as b)  as e,
(SELECT c.sdate FROM (SELECT id,s.date,
@sdate := 
(CASE
WHEN s.people >= 100 THEN @sdate
ELSE @sdate + 1 END) AS sdate,
s.people FROM stadium as s,(SELECT @sdate := 0) as b) as c WHERE c.people >= 100 
GROUP BY c.sdate HAVING COUNT(c.sdate) >=3) as d
WHERE d.sdate = e.sdate      
AND e.people >= 100;

解析:

select id,date,people from
(select temp.*,f.*,
case
when num = 1 then num
else
(case
when @previd=id-1 then @feature
else @feature:=@feature+1
end)
end as id_feature,@previd:=id
from
(select t.*,@count := @count + 1 as num from (select * from stadium where people >=
100) as t,(select @count := 0) as count) as temp,
(select @previd :=0,@feature := 1) as f) as new_temp
where id_feature in
(select id_feature1 from
(select temp1.*,f1.*,
case
when num1 = 1 then num1
else
(case
when @previd1=id-1 then @feature1
else @feature1:=@feature1+1
end)
end as id_feature1,@previd1:=id
from
(select t1.*,@count1 := @count1 + 1 as num1 from (select * from stadium where people
>= 100) as t1,(select @count1 := 0) as count1) as temp1,
(select @previd1 :=0,@feature1 := 1) as f1) as new_temp1 group by id_feature1 
having count(id_feature1)>=3);

解析:

思路:同样是添加辅助列,但与方法二不同的是。要先从stadium表中筛选出people不小于100的信息记录,
然后在筛选结果中添加一列用于表示id特征的辅助列。
对于本题来说,就是先从
id    people    
1     10       
2     109       
3     150       
4     99        
5     145       
6     1455      
7     199       
8     188 中筛选出:id    people          
2     109       
3     150              
5     145       
6     1455      
7     199       
8     188 然后,根据id的是否连续添加一列辅助列:
id    people    id_feature       
2     109       1
3     150       1      
5     145       2
6     1455      2
7     199       2
8     188       2注:基本思想就是每一组连续id都对应一个相同的@feature值,更多数据的示例如下:
id    people    id_feature          
2     109       1
3     150       1      
5     145       2
6     1455      2
7     199       2
8     188       2
15    182       3
16    189       3
28    301       4
29    556       4
30    412       4在此基础上,根据id_feature的值对数据进行分组,并根据每组内id_feature值的统计个数是否不小于3确定
满足查询要求的id_feature值,然后以这些id_feature值为条件,进一步筛选出符合查询要求的id,date,people信息。

方法三与方法二相比,添加至stadium表的辅助列中的值更容易想到,但实现辅助列内的值的代码也更复杂(有一段重复用到的代码),需要用到嵌套的case when函数,这是笔者的想法,如果有朋友有更加容易的实现方法,还请不吝赐教!

参考:

http://www.cnblogs.com/linux-java/p/9766433.html

PS:本文为博主原创文章,转载请注明出处。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部