Собесов

Glassdoor (Uber) — utilization водителя: доля времени с пассажиром

SQLTime-on-taskСложнаяSenior

Условие

Таблицы:

  • online_sessions(driver_id, online_start, online_end) — когда водитель онлайн.
  • trips(driver_id, trip_start, trip_end) — когда у него был пассажир (всегда внутри online).

Для каждого водителя за период [D1, D2] посчитайте utilization — отношение «время с пассажиром» к «время онлайн».

Решение

Шаг 1 — суммарные часы онлайн (с обрезкой по интервалу)

WITH online AS (
  SELECT driver_id,
         SUM(EXTRACT(EPOCH FROM
              LEAST(online_end, :D2) - GREATEST(online_start, :D1)
            )) AS online_seconds
  FROM online_sessions
  WHERE online_end >= :D1 AND online_start <= :D2
  GROUP BY driver_id
),

LEAST/GREATEST обрезает каждую сессию по границам периода [D1, D2].

Шаг 2 — суммарные часы поездок (так же с обрезкой)

trip AS (
  SELECT driver_id,
         SUM(EXTRACT(EPOCH FROM
              LEAST(trip_end, :D2) - GREATEST(trip_start, :D1)
            )) AS trip_seconds
  FROM trips
  WHERE trip_end >= :D1 AND trip_start <= :D2
  GROUP BY driver_id
)
SELECT
  o.driver_id,
  ROUND(COALESCE(t.trip_seconds, 0)::NUMERIC / NULLIF(o.online_seconds, 0), 4) AS utilization
FROM online o
LEFT JOIN trip t ON t.driver_id = o.driver_id
ORDER BY o.driver_id;

Если интервалы могут пересекаться

Если у одного водителя две одновременные online_sessions (баг ETL) — суммирование задвоит. Защита: схлопывать пересекающиеся интервалы (через gaps & islands по интервалам) — это отдельная сложная задача.

Подводные камни

  1. EXTRACT(EPOCH FROM interval) в Postgres даёт секунды. В MySQL — TIMESTAMPDIFF(SECOND, a, b). В Oracle — EXTRACT(SECOND FROM (b-a)).
  2. NULL на правой стороне LEFT JOIN. Если у водителя был онлайн, но не было поездок — t.trip_seconds = NULL. COALESCE(..., 0).
  3. Поездка вышла за границу online. По условию не может (trip ⊂ online), но в проде бывает (часы расходятся). Решите: clipping к union или фильтр аномалий.
  4. >= D1 AND <= D2 vs OVERLAPS. Postgres OVERLAPS оператор работает на пары интервалов. Для нашего фильтра достаточно start <= D2 AND end >= D1.

Эталонный ответ

Обрезка интервалов по [D1, D2] через LEAST/GREATEST, отдельная агрегация online и trip secunds, отношение с NULLIF. Стандарт для real-time-utilization задач.

Хочешь увидеть разбор?

Зарегистрируйся бесплатно — откроется развёрнутое решение этой задачи и ещё 4 на выбор.

Зарегистрироваться и увидеть разбор
Уже есть аккаунт? Войти