Как найти SQL-запросом самые быстрые поездки с пересадкой с автобуса на поезд?

Соединяем расписания автобусов и поездов, закладываем 15 минут на пересадку и выбираем все пары с минимальной общей продолжительностью поездки.

Короткий ответ

Что ответить на собеседовании

Сначала соедините автобус с поездами, отправляющимися не раньше его прибытия плюс время на пересадку. Затем вычислите время от отправления автобуса до прибытия поезда в Москву и выберите все пары с минимальным значением. DENSE_RANK сохранит равные лучшие варианты. При известной только верхней границе перехода в 15 минут такой запас гарантирует пересадку.

Подробный разбор

Ответ с пояснениями

Условие и допущения

Даны таблицы bus(id_bus, start_dttm, duration_trip_min) и train(id_train, start_dttm, duration_trip_min). Идентификаторы уникальны, start_dttm — отправление, продолжительность указана в минутах. Нужно вывести все пары автобус + поезд, позволяющие доехать до Москвы за минимальное время. Между прибытием автобуса и посадкой на поезд нужно пройти по площади; переход занимает не более 15 минут.

Для решения считаем, что записи относятся к совместимым маршрутам, время задано согласованно, обязательные поля заполнены, длительности неотрицательны. Минимизируем время от отправления автобуса до прибытия поезда, включая ожидание пересадки. Время ожидания первого автобуса не учитываем: исходный момент начала ожидания в задаче не указан.

Поскольку точная длительность перехода неизвестна, закладываем все 15 минут. Это консервативный вариант, гарантирующий возможность пересадки; при известном меньшем времени параметр можно заменить.

Решение на PostgreSQL

WITH routes AS (
    SELECT
        b.id_bus,
        t.id_train,
        (t.start_dttm
            + t.duration_trip_min * INTERVAL '1 minute')
            - b.start_dttm AS total_time
    FROM bus AS b
    JOIN train AS t
      ON t.start_dttm >= b.start_dttm
           + (b.duration_trip_min + 15) * INTERVAL '1 minute'
), ranked AS (
    SELECT
        id_bus, id_train, total_time,
        DENSE_RANK() OVER (ORDER BY total_time) AS position
    FROM routes
)
SELECT id_bus, id_train
FROM ranked
WHERE position = 1
ORDER BY id_bus, id_train;

Если допустимых пересадок нет, результат пуст. При одинаковой минимальной длительности возвращаются все пары: LIMIT 1 потерял бы остальные лучшие варианты.

Почему условия именно такие

Пусть автобус отправляется в 09:00 и едет 60 минут. Поезд в 10:10 не подходит при заложенном переходе в 15 минут; поезд в 10:15 подходит. Если он едет 120 минут, поездка занимает 3 часа 15 минут: от 09:00 до 12:15.

Пятнадцать минут — запас на переход, а не максимальное допустимое ожидание поезда. Верхнюю границу отправления в JOIN добавлять не нужно. Нельзя и просто выбрать ближайший поезд: более поздний поезд может ехать быстрее и прибыть раньше.

Минимальная длительность поездки отличается от самого раннего прибытия по часам. Поездка с поздним отправлением может быть короче, но закончиться позже. Если требуется именно раннее прибытие после заданного момента, нужно изменить критерий сортировки и добавить ограничение на отправление первого транспорта. Для нескольких станций понадобятся их идентификаторы и условие совместимости маршрутов; текущая схема таких полей не содержит.

Практика в реальном времени

Подготовьтесь к следующему собеседованию

Interview Boost учитывает вакансию, резюме и технологии и помогает сформулировать ответ прямо во время интервью.

Начать подготовку