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

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