Многократная сортировка в зависимости от текущего дня и завтрашнего дня (автобусные поездки) - PullRequest
1 голос
/ 23 ноября 2011

Я застрял на огромной проблеме, я скажу с моим запросом ниже. Здесь j5 представляет пятницу, а j6 - субботу (с 1 по 7 ... с воскресенья по понедельник).

Как известно, у автобусов разное расписание в зависимости от времени недели. Здесь я отправляюсь в следующие 5 поездок после 25:00:00 на cal (j5) и / или после 01:00:00 на cal2 (j6). Расписание автобусов построено так:

Если сейчас 1 час ночи, то текущее время в автобусе - 25, 2 часа ночи - 26 ... ты понял. Так что, если я хочу отправиться в поездку на сегодня после, скажем, 1 часа ночи, я могу получить только 2-3, так как «автобусный» день скоро закончится. Чтобы решить эту проблему, я хочу добавить следующий отправление со следующего дня (здесь суббота после пятницы). Но следующий день начинается в 00, как и каждый день в нашем мире.

Итак, что я хочу сделать: получить все последующие поездки в пятницу j5 после 25:00:00. Если у меня нет 5, то получите все n отправлений в поездку на субботу после 01:00:00 (с 25:00:00 = 01:00:00).

Пример: Я отправляюсь в пятницу в 25:16:00, 25:46:00 и 26:16:00. Сейчас 3. Я хочу получить еще 2 рейса на следующий день, так что в конце я получу 5, и это будет как 04:50:00 и 05:15:00. Таким образом, следующий рейс от X остановка: 25:16:00 (пятница), 25:46:00 (пятница), 26:16:00 (пятница), 04:50:00 (суббота), 05:15:00 (суббота).

У меня проблема с сортировкой обоих результатов из trips.trip_departure.

Я знаю, что это может быть сложно, мне сложно объяснить, но ... в любом случае. Есть вопрос, я здесь. Большое спасибо заранее!

PS: использование MySQL 5.1.49 и PHP 5.3.8 PS2: я хочу избежать выполнения нескольких запросов в PHP, поэтому я бы хотел сделать это в одном запросе, несмотря ни на что.

        SELECT
            trips.trip_departure,
            trips.trip_arrival,
            trips.trip_total_time,
            trips.trip_direction
        FROM
            trips,
            trips_assoc,
            (
                SELECT calendar_regular.cal_regular_id
                FROM calendar_regular
                WHERE calendar_regular.j5 = 1
            ) as cal,
            (
                SELECT calendar_regular.cal_regular_id
                FROM calendar_regular
                WHERE calendar_regular.j6 = 1
            ) as cal2
        WHERE 
            trips.trip_id = trips_assoc.trip_id
            AND
            trips.route_id IN (109)
            AND
            trips.trip_direction IN (0)
            AND
            trips.trip_period_start <= "2011-11-25"
            AND
            trips.trip_period_end >= "2011-11-25"
            AND
            (
                (
                    cal.cal_regular_id = trips_assoc.calendar_id
                        AND
                    trips.trip_departure >= "25:00:00"
                )
                OR
                (
                    cal2.cal_regular_id = trips_assoc.calendar_id
                        AND
                    trips.trip_departure >= "01:00:00"
                )
            )
        ORDER BY
            trips.trip_departure ASC
        LIMIT
            5

РЕДАКТИРОВАТЬ Структура таблицы:

Таблица calendar_regular

j1 означает воскресенье, j7 понедельник и т. Д.).

  `cal_regular_id` tinyint(3) unsigned NOT NULL AUTO_INCREMENT,
  `j1` tinyint(1) NOT NULL COMMENT 'Lundi',
  `j2` tinyint(1) NOT NULL COMMENT 'Mardi',
  `j3` tinyint(1) NOT NULL COMMENT 'Mercredi',
  `j4` tinyint(1) NOT NULL COMMENT 'Jeudi',
  `j5` tinyint(1) NOT NULL COMMENT 'Vendredi',
  `j6` tinyint(1) NOT NULL COMMENT 'Samedi',
  `j7` tinyint(1) NOT NULL COMMENT 'Dimanche',
  PRIMARY KEY (`cal_regular_id`),
  KEY `j1` (`j1`),
  KEY `j2` (`j2`),
  KEY `j3` (`j3`),
  KEY `j4` (`j4`),
  KEY `j5` (`j5`),
  KEY `j6` (`j6`),
  KEY `j7` (`j7`)   

Данные:

    cal_regular_id  j1  j2  j3  j4  j5  j6  j7
    1               0   0   0   0   1   0   0
    2               0   0   0   1   1   0   0
    3               1   1   1   1   1   0   0
    4               0   0   0   0   0   1   0
    5               0   0   0   0   0   0   1

Некоторые автобусы доступны x дней, это таблица, определяющая время недели ... назначенная таблице trip_assoc.

Таблица поездок

  `agency_id` smallint(5) unsigned NOT NULL,
  `trip_id` binary(16) NOT NULL,
  `trip_period_start` date NOT NULL,
  `trip_period_end` date NOT NULL,
  `trip_direction` tinyint(1) unsigned NOT NULL,
  `trip_departure` time NOT NULL,
  `trip_arrival` time NOT NULL,
  `trip_total_time` mediumint(8) NOT NULL,
  `trip_terminus` mediumint(8) NOT NULL,
  `route_id` mediumint(8) NOT NULL,
  `shape_id` binary(16) NOT NULL,
  `block` binary(16) DEFAULT NULL,
  KEY `testing` (`route_id`,`trip_direction`),
  KEY `trip_departure` (`trip_departure`)

таблица trips_assoc

  `agency_id` tinyint(4) NOT NULL,
  `trip_id` binary(16) NOT NULL,
  `calendar_id` smallint(6) NOT NULL,
  KEY `agency_id` (`agency_id`),
  KEY `trip_id` (`trip_id`,`calendar_id`)

Ответы [ 2 ]

2 голосов
/ 23 ноября 2011

Во-первых, НИКОГДА позволяет внешнему объекту диктовать неуникальный столбец соединения.Они могут (с авторизацией / аутентификацией) диктовать уникальные единицы (как детерминированное значение GUID).В противном случае они могут где-то диктовать ключ natural , и ваша база данных автоматически назначает идентификаторы строк для присоединения.Кроме того, если вы не имеете дело с огромным числом объединений (несколько десятков) по неиндексированным строкам, производительность будет гораздо менее значимым фактором, чем головные боли при работе с ним в других местах.

Итак, судя по всему, вы храните расписание автобусов от нескольких компаний (что-то вроде google, должно быть, для получения маршрутов общественного транспорта, да).
Вот как я бы с этим справился:

  • Вам понадобится файл календаря .Это полезно для всех бизнес-сценариев, но будет чрезвычайно полезно здесь (примечание: не помещайте в него никакой информации, связанной с маршрутом).

  • Измените свою таблицу agency для контролясоединить ключи.Агентства не получают возможность указывать свои идентификаторы, только свои имена (или некоторый аналогичный идентификатор).Должно быть что-то вроде следующего:

    agency
    =============
    id      - identity, incrementing
    name    - Externally specified name, unique
    
  • Измените таблицу route для управления ключами соединения.Агентства должны иметь возможность указывать только свои (потенциально неуникальные) натуральные ключи, поэтому нам нужен суррогатный ключ для объединений:

    route
    ==============
    id                - identity, incrementing
    agency_id         - fk reference to agency.id
    route_identifier  - natural key specified by agency, potentially non-unique.
                      - required unique per agency_id, however (or include variation for unique)
    route_variation   - some agencies use the same routes for both directions, but they're still different.
    route_status_id   - fk reference to route_status.id (potential attribute, debatable)
    

    Обратите внимание, чтотаблица маршрутов не должна фактически перечислять остановок , которые находятся на маршруте - единственная цель состоит в том, чтобы контролировать, какое агентство имеет какие маршруты.

  • Создать location или address таблица.Это принесет вам наибольшую пользу в том, что большинство транзитных компаний имеют тенденцию прокладывать несколько маршрутов через одни и те же места:

    location
    =============
    id        - identity, incrementing
    address   - there are multiple ways to represent addresses in a database.  
              - if nothing else, seperating the fields should suffice
    lat/long  - please store these properly, not as a single column.
              - two floats/doubles will suffice, although there are some dedicated solutions.
    
  • На данный момент у вас есть два варианта работы с остановкамимаршрут:

    1. Определите таблицу stop и перечислите все остановки.Примерно так:

      stop
      ================
      id           - identity, incrementing
      route_id     - fk reference to route.id
      location_id  - fk reference to location.id
      departure    - Timestamp (date and time) when the route leaves the stop.  
      

      Это, конечно, очень быстро становится большим, но облегчает работу с расписаниями праздников.

    2. Определите schedule набор таблиц, иschedule_override столовый набор:

      schedule
      ===================
      id           - identity, incrementing
      route_id     - fk reference to route.id
      start_date   - date schedule goes into effect.
      
      schedule_stop
      ===================
      schedule_id  - fk reference to schedule.id
      location_id  - fk reference to location.id
      departure    - Time (time only) when the route leaves the stop 
      dayOfWeek    - equivalent to whatever is in calendar.nameOfDay
                   - This does not have to be an id, so long as they match
      
      schedule_override
      ===================
      id             - identity, incrementing
      route_id       - fk reference to route.id
      effective_date  - date override is in effect.  Should be listed in the calendar file.
      reason_id      - why there's an override in effect.
      
      schedule_override_stop
      ===========================
      schedule_override_id  - fk reference to schedule_override.id
      location_id           - fk reference to location.id
      departure             - time (time only) when the route leaves the stop
      

С помощью этой информации теперь я могу получить необходимую информацию:

SELECT
FROM agency as a
JOIN route as b
ON b.agency_id = a.id
AND b.route_identifier = :(whatever 109 equates to)
AND b.route_variation = :(whatever 0 equates to)
JOIN (SELECT COALESCE(d.route_id, j.route_id) as route_id, 
             COALESCE(e.location_id, j.location_id) as location_id,
             COALESCE(TIMESTAMP(c.date, e.departure), 
                      TIMESTAMP(c.date, j.departure)) as departure_timestamp
      FROM calendar as c
      LEFT JOIN (schedule_override as d
                 JOIN schedule_override_stop as e
                 ON e.schedule_override_id = d.id)
      ON d.effective_date = c.date
      LEFT JOIN (SELECT f.route_id, f.start_date
                        g.dayOfWeek, g.departure, g.location_id,
                        (SELECT MIN(h.start_date)
                         FROM schedule as h
                         WHERE h.route_id = f.route_id
                         AND h.start_date > f.start_date) as end_date
                 FROM schedule as f
                 JOIN schedule_stop as g
                 ON g.schedule_id = f.id) as j
      ON j.start_date <= c.date
      AND j.end_date > c.date
      AND j.dayOfWeek = c.dayOfWeek
      WHERE c.date >= :startDate
      AND c.date < :endDate) as k
ON k.route_id = b.id
AND k.departure_timestamp >= :leaveAfter
JOIN location as m
ON m.id = k.location_id
AND m.(location inforation) = :(input location information)
ORDER BY k.departure_timestamp ASC
LIMIT 5

Это даст список всех отправлений, отправляющихся из указанного местоположения, для данного маршрута, между startDate и endDate (не включая) и после отметки времени leaveAfter.Оператор (эквивалент) работает в DB2.Он собирает изменения в расписаниях, переопределения на праздники и т. Д.

0 голосов
/ 23 ноября 2011

Я думаю, что совет X-Zero - лучшее решение, но у меня было свободное время :) Пожалуйста, смотрите ниже, я использовал concat для обработки в качестве метки времени и после того, как заказал эти два столбца. Я написал от руки может быть ошибка, я использовал существует, где-то я читаю его быстрее, чем соединение, но вы можете просто использовать concat и упорядочить части запроса

 SELECT
        trips.trip_departure,
        trips.trip_arrival,
        trips.trip_total_time,
        trips.trip_direction,
        CONCAT(trips.trip_period_start,' ',trips.trip_departure) as start,
        CONCAT(trips.trip_period_end,' ',trips.trip_departure) as end,
    FROM trips
    WHERE EXISTS
          (
            SELECT
              trips_assoc.calendar_id
            FROM
              trips_assoc
            WHERE
              trips.trip_id = trips_assoc.trip_id
            AND EXISTS
                (
                   SELECT
                      calendar_regular.cal_regular_id
                   FROM
                      calendar_regular
                   WHERE
                      cal2.cal_regular_id = trips_assoc.calendar_id
                   AND
                     (
                        calendar_regular.j5 = 1
                        OR
                        calendar_regular.j6 = 1
                     )      
                )
           )
    AND
           trips.route_id IN (109)
    AND
           trips.trip_direction IN (0)
    AND
           trips.trip_period_start <= "2011-11-25"
    AND
           trips.trip_period_end >= "2011-11-25"
    AND
          (
             trips.trip_departure >= "25:00:00"
             OR
             trips.trip_departure >= "01:00:00"
          )
    ORDER BY
          TIMESTAMP(start) ASC,TIMESTAMP(end) ASC
    LIMIT
          5

РЕДАКТИРОВАТЬ: исправлена ​​ошибка КОПИЯ / ПАСТА

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...