Собесов

LeetCode SQL — Trips and Users: cancellation rate за период

SQLМноготабличные джойныСложнаяMiddle

Условие

Таблицы:

  • Trips(id, client_id, driver_id, city_id, status, request_at)status ∈ {completed, cancelled_by_driver, cancelled_by_client}.
  • Users(users_id, banned, role)banned ∈ {Yes, No}, role ∈ {client, driver, partner}.

Для каждого дня в интервале 2013-10-01..2013-10-03 посчитайте Cancellation Rate — долю отменённых поездок среди тех, где ни клиент, ни водитель не забанены. Округление до 2 знаков. Дни без не-забаненных поездок не показывать.

Решение

Подход

  1. Отфильтровать Users до не-забаненных по двум ролям.
  2. JOIN дважды (по client_id и driver_id) или EXISTS-фильтр.
  3. Условная агрегация AVG(CASE WHEN status LIKE 'cancelled%' THEN 1 ELSE 0 END).
SELECT
  request_at AS Day,
  ROUND(
    AVG(CASE WHEN status <> 'completed' THEN 1.0 ELSE 0 END),
    2
  ) AS "Cancellation Rate"
FROM Trips t
WHERE request_at BETWEEN '2013-10-01' AND '2013-10-03'
  AND client_id NOT IN (SELECT users_id FROM Users WHERE banned = 'Yes')
  AND driver_id NOT IN (SELECT users_id FROM Users WHERE banned = 'Yes')
GROUP BY request_at
ORDER BY request_at;

Эквивалент через JOIN

SELECT t.request_at AS Day,
       ROUND(SUM(CASE WHEN status <> 'completed' THEN 1 ELSE 0 END)::DECIMAL
             / COUNT(*), 2) AS "Cancellation Rate"
FROM Trips t
JOIN Users uc ON uc.users_id = t.client_id AND uc.banned = 'No'
JOIN Users ud ON ud.users_id = t.driver_id AND ud.banned = 'No'
WHERE t.request_at BETWEEN '2013-10-01' AND '2013-10-03'
GROUP BY t.request_at;

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

  1. status — две разных «отмены». Любая cancelled_* идёт в числитель. Проще писать status <> 'completed'.
  2. NOT IN с NULL. Если в Users есть users_id IS NULL, NOT IN вернёт пусто. Если такое возможно — NOT EXISTS или фильтр WHERE users_id IS NOT NULL.
  3. AVG vs SUM/COUNT. AVG(CASE ... THEN 1.0 ELSE 0) неявно даёт долю — но в MySQL нужно 1.0, иначе целочисленное деление.

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

Отфильтровать забаненных клиентов и водителей, потом AVG(CASE WHEN status <> 'completed' THEN 1.0 ELSE 0 END). Округление до 2 знаков.

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

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

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