解题关键:搞清用户停止等待的所有情况

各城市最大同时等车人数

http://www.nowcoder.com/practice/f301eccab83c42ab8dab80f28a1eef98

本题是一道典型的计算瞬时最大值问题,基本思路类似以下这题:

https://blog.nowcoder.net/n/18b5596467a643e58e0acd23cf3fae5b

本题的难点在于准确理解【用户在何时会终止等待的状态】。

在这里,我们想象一下,自己刚刚下班,准备叫滴滴,我们会停止等车的所有情况包括:

1、【未接单取消】

在发出打车指令后,司机接单前,订单取消(用户主动取消,或是等待超时导致系统强制取消);

2、【接单取消】

在司机接单后,尚未抵达(用户未上车)前,用户或司机取消订单;

3、【上车】

用户顺利上车,结束等待。

结合上述思考,我们进行如下的编码联立:

SELECT city, event_time dt, order_id, 1 diff #开始等待,人数+1
FROM tb_get_car_record
WHERE LEFT(event_time, 7) = '2021-10'
UNION
SELECT city, o.start_time dt, r.order_id, -1 diff #顺利上车,人数-1
FROM tb_get_car_record r
LEFT JOIN tb_get_car_order o USING(order_id)
WHERE LEFT(o.start_time, 7) = '2021-10'
      AND
      start_time IS NOT NULL
UNION
SELECT city, o.finish_time dt, r.order_id, -1 diff #上车前取消,人数-1
FROM tb_get_car_record r
LEFT JOIN tb_get_car_order o USING(order_id)
WHERE LEFT(o.finish_time, 7) = '2021-10'
      AND
      start_time IS NULL

基于原数据的逻辑解释,我们知道了,只要用户没有顺利上车,提前结束的时间就会记录为finish_time, 因此上述的【未接单取消】、【接单取消】这两种情况都包含在finish_time里面了。

接下来,我们按部就班地进行开窗统计好了。

(注意:要对城市city,和日期DATE(dt) 进行聚合)

代码如下:

WITH t AS(
SELECT city, event_time dt, order_id, 1 diff #开始等待,人数+1
FROM tb_get_car_record
WHERE LEFT(event_time, 7) = '2021-10'
UNION 
SELECT city, o.start_time dt, r.order_id, -1 diff #顺利上车,人数-1
FROM tb_get_car_record r
LEFT JOIN tb_get_car_order o USING(order_id)
WHERE LEFT(o.start_time, 7) = '2021-10'
      AND 
      start_time IS NOT NULL
UNION
SELECT city, o.finish_time dt, r.order_id, -1 diff #上车前取消,人数-1
FROM tb_get_car_record r
LEFT JOIN tb_get_car_order o USING(order_id)
WHERE LEFT(o.finish_time, 7) = '2021-10'
      AND 
      start_time IS NULL
)

SELECT 
  city,
  MAX(instant_wait_cnt) max_wait_uv
FROM (
  SELECT 
    city,
    DATE(dt) dt,
    SUM(diff) OVER (PARTITION BY city, DATE(dt) ORDER BY dt, diff DESC) instant_wait_cnt
  FROM t
) a
GROUP BY 1
ORDER BY 2, 1


其他不能理解的细节问题,请移步这里:

https://blog.nowcoder.net/n/18b5596467a643e58e0acd23cf3fae5b

全部评论
unoin那里感觉还可以改进一下,用ifnull(start_time,finish_time)会简洁一点
1 回复 分享
发布于 2021-12-05 19:20
有两个问题: 1.司机未接单取消订单的情况是记录到endtime中,所以等待人数-1的情况有三种,优先级关系为 starttime > finishtime>endtime 2.dt命名,一开始指的是datetime,后来date也用dt,容易混淆,因为开窗函数后边的order by有dt
1 回复 分享
发布于 2022-03-17 17:34
司机接单前取消订单的情况,并不会有finis_time,只有end_time,故合并查询应该增加以下语句 union select(city,end_time dt,order_id,-1 diff from tb_get_car_record where order_id is null )
3 回复 分享
发布于 2022-06-01 00:55
想请问下,为什么是选取的是r.order_id,而不是o.order_id,这两个有什么区别吗;还有为什么要用r表的left join呢
点赞 回复 分享
发布于 2022-01-14 16:08
partition by加上按日期分类的话,我觉得如如果昨天还有两个人在等车(跨天),分类之后这两个人就不算在第二天,反而会出问题
点赞 回复 分享
发布于 2022-02-18 18:15
order by dt 的作用是什么?可以不放吗?
点赞 回复 分享
发布于 2022-06-22 18:25

相关推荐

2024-12-12 15:07
已编辑
门头沟学院 Java
秋招end未来可期:实习内容太多了,抓不住重点,关键还是用了什么技术解决了什么问题,得到了什么样的效果,另外专业技能有点少,可以网上去找一些别人的简历来参考参考。整体内容够了,估计就是一些内容调整了。
点赞 评论 收藏
分享
评论
16
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务