Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/61.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql SQL表设计-存储一次行程的多个分支_Mysql_Sql_Database Design - Fatal编程技术网

Mysql SQL表设计-存储一次行程的多个分支

Mysql SQL表设计-存储一次行程的多个分支,mysql,sql,database-design,Mysql,Sql,Database Design,我想创建一个数据库来存储行程的各个分支,其中每个分支在另一个表中都有一个FK。行程标识符将是键/唯一的 例如,“东海岸公路之旅”:波士顿->纽约,纽约->费城,费城->巴尔的摩,巴尔的摩->华盛顿,华盛顿->罗利” 稍后,我希望运行以下查询: "Which trips contain the NYC -> Philly and Philly -> Baltimore legs?" 对于如何有效地存储这样的旅行信息,我感到有点困惑。使用trip标识符键并将trip分支存储为纯文本列可

我想创建一个数据库来存储行程的各个分支,其中每个分支在另一个表中都有一个FK。行程标识符将是键/唯一的

例如,“东海岸公路之旅”:波士顿->纽约,纽约->费城,费城->巴尔的摩,巴尔的摩->华盛顿,华盛顿->罗利”

稍后,我希望运行以下查询:

"Which trips contain the NYC -> Philly and Philly -> Baltimore legs?"
对于如何有效地存储这样的旅行信息,我感到有点困惑。使用trip标识符键并将trip分支存储为纯文本列可能不是最有效的解决方案


如果您能给我一些建议,我将不胜感激。

有一个
行程表,它与
腿有1:多的关系。支腿将包含
外键到
位置

然后,您可以通过从任意多个
分支
中执行
选择
来执行查询,每个分支都被别名为不同的名称,并确保它们都具有相同的
trip\u id

可能是这样的:

SELECT
    trip.name
FROM
    trip
    INNER JOIN leg leg1 ON (trip.id = leg1.trip_id)
    INNER JOIN leg leg2 ON (trip.id = leg2.trip_id)
    INNER JOIN location location_from1 ON (
        location_from1.id = leg1.location_from_id
    )
    INNER JOIN location location_to1 ON (
        location_to1.id = leg1.location_to_id)
    )
    INNER JOIN location location_from2 ON (
        location_from2.id = leg2.location_from_id
    )
    INNER JOIN location location_to2 ON (
        location_to2.id = leg2.location_to_id
    )
WHERE
    location_from1.name = 'NYC'
    AND location_to1.name = 'Philly'
    AND location_from2.name = 'Philly'
    AND location_to2.name = 'Baltimore'

但是,所有这些额外的位置联接都很昂贵,因此您可能希望在查询之前查找各个位置的主键,然后只需将
WHERE
子句添加到leg表中即可。

听起来相当简单

你想要一张旅行表,上面有旅行id,可能有“东海岸公路旅行”之类的标签,可能有日期、旅行对象、出发日期/时间,或者其他什么

您可能需要一个节点表,以存储城市(“波士顿”、“费城”等)或每个分支的起点和终点。因此,这将包含一个节点id及其名称或标签

行程的每条航段连接两个节点。您需要一个trip_leg表,其中包含trip_id、from_node_id和to_node_id。您可能需要其他信息,例如到达目的地的日期/时间

  SELECT t.label
    FROM trips as t
    INNER JOIN trip_legs as x1  ON (t.trip_id = x1.trip_id)
    INNER JOIN trip_legs as x2  ON (t.trip_id = x2.trip_id 
                                AND x1.to_node_id = x2.from_node_id)
    WHERE x1.from_node_id IN (SELECT node_id FROM nodes WHERE name = "NYC")
      AND x1.to_node_id   IN (SELECT node_id FROM nodes WHERE name = "Philly")
      AND x2.to_node_id   IN (SELECT node_id FROM nodes WHERE name = "Baltimore")

我将创建以下内容:

一个位置表,其中包含每个可能的位置和一个ID值

CREATE TABLE Location(
    LocationID int NOT NULL AUTO_INCREMENT,
    Location nchar(10) NOT NULL,
    PRIMARY KEY 
(LocationID) 
);
一个腿表,包括旅行的每一条腿。它有一个腿的ID,以及作为位置表外键的起点和终点的位置ID

CREATE TABLE Leg(
    LegID int NOT NULL AUTO_INCREMENT,
    Origin int NOT NULL,
    Destination int NOT NULL,
PRIMARY KEY(LegID) 
);

FOREIGN KEY(Origin) REFERENCES Location(LocationID)

FOREIGN KEY(Destination) REFERENCES Location(LocationID)
包含行程各航段的行程表,是行程ID和基本细节:

CREATE TABLE Trip(
    TripID int NOT NULL AUTO_INCREMENT,
PRIMARY KEY (TripID)
);
三重表,通过三重表和LegID连接行程和腿部细节

CREATE TABLE TripLeg(
    LegID int NOT NULL,
    TripID int NOT NULL,
PRIMARY KEY (LegID ,TripID)
);

FOREIGN KEY(LegID) REFERENCES Leg(LegID)
FOREIGN KEY(TripID) REFERENCES Trip(TripID)

这将允许您根据城市、单程或总行程进行查询。希望这能有所帮助。

假设您的行程不是“一次性”的,而是在预定线路上进行的(并且一条线路可以生成多个行程),那么您将需要以下内容:

TRIP: LINE_ID  TRIP_NO
      -------  -------
          100       23

LINE: LINE_ID  LINE_NAME
      -------  ---------
          100  'East coast roadtrip'

LEG:  LINE_ID  LEG_NO  STOP_ID
      -------  ------  -------
          100       1       55
          100       2       11
          100       3       66
          100       4       22
          100       5       44
          100       6       33

STOP: STOP_ID  STOP_NAME
      -------  ---------
           22  'Baltimore'
           11  'NYC'
           33  'Raleigh'
           66  'Philly'
           55  'Boston'
           44  'DC'

(如果他们是一次性的,想象一下这条线就是旅程。)

注意腿的结构:

  • 其主键包含LEG_NO,但不包含STOP_ID:LEG_NO确定给定行中腿的顺序,并允许多个腿在必要时(例如往返)穿过同一个站
  • 此外,腿中只有“开始”(而不是“结束”)停止-无论“之前”(由腿号定义)腿决定下一腿的开始停止。这样,您就永远不会有断开连接的腿(即前一腿的结束停止与下一腿的开始停止不匹配)
行程的主键包含行程号,而不是(例如)开始日期时间,以允许在需要时在同一线路上同时开始多个行程

示例“东海岸公路旅行”线路上的第23次旅行可以表示为:

TRIP: LINE_ID  TRIP_NO
      -------  -------
          100       23

LINE: LINE_ID  LINE_NAME
      -------  ---------
          100  'East coast roadtrip'

LEG:  LINE_ID  LEG_NO  STOP_ID
      -------  ------  -------
          100       1       55
          100       2       11
          100       3       66
          100       4       22
          100       5       44
          100       6       33

STOP: STOP_ID  STOP_NAME
      -------  ---------
           22  'Baltimore'
           11  'NYC'
           33  'Raleigh'
           66  'Philly'
           55  'Boston'
           44  'DC'
(注意:我有意使用非序列号来更清晰地勾勒出连接。)


使用此数据库结构,您可以轻松获得经过所有给定站点的行程,例如:

SELECT *
FROM TRIP
WHERE
    LINE_ID IN (
        SELECT LINE_ID
        FROM LEG JOIN STOP ON LEG.STOP_ID = STOP.STOP_ID
        WHERE STOP_NAME IN ('NYC', 'Philly', 'Baltimore')
        GROUP BY LINE_ID
        HAVING COUNT(DISTINCT STOP_ID) = 3
    )
(注意:在较旧版本的MySQL上,由于查询优化器在中存在问题,您可能希望将此查询重写为JOIN。)


然而,如果你想按顺序通过这些站点,并且中间没有“空隙”,那么大腿会很快变得毛茸茸的。可能您最好的选择是获取上面子查询的结果并在客户端对其进行分析,而不是尝试在SQL(基本上是基于集合的)中建立顺序并检测差距。

这是我的想象,还是这是对mySQL问题的TSQL回答?;-)是的,我没有mySQL,但我想给您提供我将用于构建数据库的表定义。设计是一样的,比如说,提供一个高效的DB2解决方案是没有用的,因为我会使用公共表表达式,这在mySQL中是不可用的。同样地,许多TSQL构造也不可用。我建议去掉TSQL的东西,我想可能还有
[]
括号-MySQL会被这些东西卡住。做得好,解决了1->2和2->3不能立即连接的问题。还有一张图表+1谢谢你,布兰科,我真的很感谢你花了这么多时间来讨论这些细节!