mysql - 根据当天和明天进行多重排序(公交车次)

标签 mysql sql database

我遇到了一个巨大的问题,我将在下面的查询中说。这里 j5 代表星期五,j6 代表星期六(1 到 7...星期日到星期一)。

如您所知,巴士根据一周中的不同时段有不同的时刻表。在这里,我将在 cal (j5)25:00:00 之后和/或 01:00:00 之后进行接下来的 5 次旅行在 cal2 (j6) 上。公交时刻表是这样构建的:

如果现在是凌晨 1 点,那么当前的公交车时间是 25 点,凌晨 2 点是 26 点……你明白了。因此,如果我今天想在凌晨 1 点之后出发,我可能只有 2-3 点,因为“公共(public)汽车”日很快结束。为了解决这个问题,我想添加从第二天开始的下一类出发(这里是周五之后的周六)。但是第二天就像我们世界上的每一天一样从 00 点开始。

所以我想做的是:获取周五 j5 25:00:00 之后的所有下一次行程。如果我没有 5,则获取星期六 01:00:00 之后的所有 n 次行程出发(因为 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

一些公共(public)汽车可用 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`)

最佳答案

首先,绝不 让外部实体指定一个非唯一的连接列。他们可能(通过授权/身份验证)指示唯一(如确定性 GUID 值)。否则,他们会在某处指示一个自然键,并且您的数据库会自动分配用于连接的行 ID。此外,除非您在未索引的行上处理大量 的连接(数十个),否则性能将远不及在其他地方处理它的麻烦。

因此,从表面上看,您正在存储来自多家公司的公交时刻表(谷歌必须这样做才能获取公共(public)交通路线,是的)。
下面是我将如何处理这个问题:

  • 你需要一个 calendar file .这对所有业务场景都有用,但在这里将非常有用(注意:不要在其中放置任何与路线相关的信息)。

  • 修改您的 agency 表以控制连接键。机构不会指定他们的 ID,只能指定他们的名字(或一些类似的标识符)。像下面这样的东西就足够了:

    agency
    =============
    id      - identity, incrementing
    name    - Externally specified name, unique
    
  • 修改您的路由 表以控制连接键。机构应该只能指定他们的(可能是非唯一的)自然键,所以我们需要一个代理键来连接:

    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)
    

    请注意,路线表实际上不应列出路线上的停靠站 - 它的唯一目的是控制哪个机构拥有哪些路线。

  • 创建一个locationaddress 表。这将使您受益最大,因为大多数运输公司往往会在同一地点设置多条路线:

    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

这将给出从指定位置出发的所有出发列表,对于给定路线,startDateendDate(不包括)之间,以及 之后leaveAfter 时间戳。语句(等效)在 DB2 上运行。它获取日程安排的更改、假期的覆盖等。

关于mysql - 根据当天和明天进行多重排序(公交车次),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8235317/

相关文章:

mysql - 从 MySQL 服务器查询 MS-SQL 服务器

mysql - 在 like 语句中使用 mysql 变量进行 SQL 查询?

mysql - 使用 IF-END IF 定义 MySQL 函数时出错

c++ - QT中用构造函数初始化对象,没有匹配的函数可以调用

mysql - Node JS和mysql连接不上(客户端不支持服务端请求的认证协议(protocol),考虑升级mysql客户端)

php - 如何在另一个 PHP 页面中显示信息

sql - BETWEEN 子句与 <= AND >=

mysql - SELECT WITH LEFT JOIN 和 WHERE 子句

python - Tweepy 不将重复的推文存储到数据库中

php - 如何用 ENUM 值填充 <select>?