思路:
①将用户的进入时间单独拎出来,同时记为1;离开时间单独拎出来,同时记为-1,这样就聚合这两个表,按照时间排序,意思就是:进去一个加1,离开一个减1。
②然后利用窗口函数对计数(1或者-1)求累计和,因为题目规定:同一时间有就有出的话先算进来的后算出去的,所以排序的时候就要看好了先按时间排序,再按计数排序!
③然后再在每个分组里面去求最大的累积和就是最多同时在线的人数了!
例题1:每篇文章同一时刻最大在看人数
select artical_id,max(cnt)as max_uv
from(
select artical_id,sum(num)over(partition by artical_id order by dt asc,num desc )as cnt from (
select artical_id,in_time dt,1 num from tb_user_log
where artical_id != 0
union all
(select artical_id,out_time dt,-1 num from tb_user_log
where artical_id !=0)) a
)b
group by artical_id
order by max_uv desc
例题2:各城市最大同时等车人数
思路:同上
不同点:需要对等车结束时间做辨别,
- 同时等车:开始时间均为
event_time
,结束时间不同- 对于没有接单的用户(order_id为空),结束时间为记录表中的
end_time
- 对于接单后取消订单的用户(start_time为空),结束时间为订单表中的
finish_time
- 对于完成订单的用户(start_time不为空),结束时间为订单表中的
start_time
,start_time
表示上车时间 -
WITH t1 AS ( SELECT city, event_time, (CASE WHEN tb_get_car_record.order_id IS NULL THEN end_time WHEN start_time IS NULL THEN finish_time WHEN start_time IS NOT NULL THEN start_time END) e_time FROM tb_get_car_record LEFT JOIN tb_get_car_order ON tb_get_car_record.order_id=tb_get_car_order.order_id WHERE DATE(event_time) BETWEEN '2021-10-1'AND '2021-10-31') select city,max(wait_uv) as max_wait_uv from ( select city,sum(num)over(partition by city order by dt asc,num desc) as wait_uv from ( select city,event_time as dt, 1 num from t1 union all (select city,e_time as dt,-1 num from t1) )a) b group by city order by max_wait_uv ,city
- 对于没有接单的用户(order_id为空),结束时间为记录表中的
例题3:牛客直播各科目同时在线人数
with t1 as(select a.course_id,a.in_datetime,a.out_datetime,b.course_name
from attend_tb a left join course_tb b
on a.course_id=b.course_id)
select course_id,course_name,max(num) as max_num from (
select course_id,course_name,sum(num)over(partition by course_id order by dt) as num from
(select course_id,course_name,in_datetime dt,1 num
from t1
union all
(select course_id,course_name,out_datetime dt,-1 num
from t1)) t2)t3
group by course_id,course_name
order by course_id