一尘不染

根据当日和明天(公共汽车旅行)进行多种分类

sql

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

如您所知,公交车有不同的时间表,具体取决于一周中的时间。在这里,我服用后未来5个车次出发25:00:00cal (j5)和/或后01:00:00cal2 (j6)。公交车时刻表是这样构建的:

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

因此,我想做的是:j5在25:00:00之后获得星期五的所有下次旅行。如果我没有5,则在01:00:00(因为25:00:00 =
01:00:00)之后的星期六获得全部n次旅行。

示例:我在星期五的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`)

阅读 136

收藏
2021-05-16

共1个答案

一尘不染

首先, _ 永远不要 让外部实体指定非唯一的连接列。它们可能(具有授权/认证)可以指示 _唯一
的(例如确定性GUID值)。否则,他们将在某个地方指定一个 自然 键,并且您的数据库会自动分配要加入的行ID。另外,除非您要处理未索引行上的 大量
联接(数十个),否则性能将远不及在其他地方处理它时的麻烦。

因此,从外观上看,您正在存储多家公司的公交车时刻表(类似于google,这是获取公共交通路线的必经之路)。
这是我要如何处理:

  • 您将需要一个日历文件。这对于所有业务场景都是有用的,但是在这里将非常有用(请注意:不要在其中添加任何与路由相关的信息)。

  • 修改agency表以控制联接键。代理商 无法 指定其ID,只能指定其名称(或一些类似的标识符)。如下所示就足够了:

    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)

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

  • 创建一个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

这将列出从指定位置出发的所有出发点的清单,对于给定的路线,在startDate和之间endDate(不包括),在leaveAfter时间戳之后。语句(等效)在DB2上运行。它获取时间表的更改,节假日的替代等。

2021-05-16