2013-03-23 90 views
2

我想创建一个数据库来存储旅行的腿,其中每条腿在另一个表中具有FK,旅行标识符将是关键/唯一。SQL表格设计 - 存储旅程的多条腿

E.g. “ '东海岸的旅游路径':波士顿 - >纽约,纽约市 - >费城,费城 - >巴尔的摩,巴尔的摩 - > DC,DC - >罗利”

后来,我想运行查询,例如,

"Which trips contain the NYC -> Philly and Philly -> Baltimore legs?" 

我有点难以确定如何有效地存储这种旅行信息。行程标识符键并将行程分支存储为纯文本列可能不是最有效的解决方案。

希望有关如何解决这个问题的任何提示。

回答

2

假设你的行程是不是“取舍”,而是被预定线路进行(和单行可以产生多次往返),那么你就需要这样的事:

enter image description here

(如果他们一次性的,试想行是一趟)

注重腿部的结构:

  • 其PK包含LEG_NO,但不包含STOP_ID:LEG_NO确定给定行中腿的顺序,并且还允许多个腿在必要时穿过相同的停止位置(例如,往返)。
  • 此外,在腿中只有“开始”(而不是“结束”)停止 - 无论是“前一个”(由LEG_NO定义),腿都确定下一个腿的起始停止。这样,你永远不会有断开的腿(即前一条腿的结束停止与下一条腿的起始停止不匹配)。

的TRIP的PK包含TRIP_NO而不是(例如)START_DATE_TIME,允许多次往返将在同一时间在同一行开始,你应该永远需要这一点。

在你的榜样“东海岸的旅游路径”线可以表示像这样的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中的差距(这基本上是基于集合的)。

+1

良好的工作,处理1-> 2和2-> 3问题没有立即连接。还有一张图! +1 – halfer 2013-03-24 11:12:58

+0

谢谢Branko,我非常感谢你花时间去细节! – r3su 2013-03-24 19:23:33

1

有一个trip表,它与leg有1:多关系。这条支路将包含tofrom外键给location

然后,您可以从许多leg在做一个SELECT做你的查询,只要你喜欢,每一个被别名为一个不同的名称,并确保它们都具有相同的trip_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条款的腿表。

2

听起来很简单。

你想要一个旅行表,带有trip_id,也许是一个标签,例如“East coast roadtrip”,也许日期,旅行日期,出发日期/时间等等。

您可能需要一个节点表来存储城市(“波士顿”,“费城”等)或任何地方是您每条腿的开始和结束点。所以这将包含一个node_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") 
2

我将创建以下:

其具有每个位置可能的位置表和ID值

CREATE TABLE Location(
    LocationID int NOT NULL AUTO_INCREMENT, 
    Location nchar(10) NOT NULL, 
    PRIMARY KEY 
(LocationID) 
); 

腿表,其包括跳闸的每个腿。它有让腿部与出发地和目的地都一个位置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和旅行表中的ID基本资料:

CREATE TABLE Trip(
    TripID int NOT NULL AUTO_INCREMENT, 
PRIMARY KEY (TripID) 
); 

一个TripLeg表,加入了旅行和腿的细节与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) 

这将允许您根据城市,个别腿或总TR查询IP。希望这可以帮助。

+0

是我的想象,还是这是一个TSQL答案的MySQL问题? ;-) – WarrenT 2013-03-23 01:10:06

+1

是的,我没有mySQL,但想给你我将用于构建数据库的表定义。设计将是相同的。 – Harrison 2013-03-23 01:13:54

+0

举例来说,提供高效的DB2解决方案本来是没有用的,因为我会使用公用表表达式,这在mySQL中是不可用的。同样,许多TSQL构造也不可用。 – WarrenT 2013-03-23 01:30:13