# 时间线扫描法 # 先合并所有表格,并且注意,可能存在用户取消订单情况,所以要用left join,并且筛选出2021年10月订单 with t0 as( select r.uid,r.order_id,city, event_time,end_time, driver_id,order_time, start_time, finish_time from tb_get_car_record r left join tb_get_car_order o on r.order_id = o.order_id where date_format(event_time,"%Y-%m") = "2021-10" ), # 开始等车时间: 所有的情况下,开始时间都是event_time-打车时间 # 开始等车的人次被计作 1,如果有人开始等车,则 +1 start_time as ( select city,uid,order_id, 1 as mark,event_time as time from t0 ), # 停止等车时间: # 根据题目叙述来梳理,可以画一个图来看, # 如果打车成功,order_time 和start_time 都不为空,停止等车时间就是上车时间start_time; # 如果无人接单,order_time 和start_time 都为空,停止等车时间就是订单结束时间end_time; # 如果接单了但取消订单了,那么order_time不为空, start_time 都为空,停止等车时间就是订单完成时间finish_time. # 停止等车的人次别计作 -1, 如果有人停止等车,则-1 end_wait_time as( select city, uid, order_id, -1 as mark, case when order_time is not null and start_time is not null then start_time when order_time is null and start_time is null then end_time when order_time is not null and start_time is null then finish_time else "none" end as time from t0 ), # 时间线扫描,合并所有的动作 time_line as( select * from start_time union all select * from end_wait_time ), # 按照时间,和动作排序,在每个时间点,计算从一开始到现在,上车人次和下车人次之和,就是这个时间点上的同时在等车的人数。最后,形成每个时间点上的同时等车人数 f as( select *, sum(mark) over(order by time rows between unbounded preceding and current row) as cnt from time_line order by time, uid ) # 根据城市分组,选择每个城市最大的同时在线人数。 select city, max(cnt) as max_wait_uv from f group by city order by max_wait_uv, city