用于检索连接列车的SQL查询

时间:2009-11-04 14:01:45

标签: sql

我有一个包含很多列车时间的数据库,适用于很多不同的列车。它看起来像这样:

表1

Station_id Station_name 等

表2

StationName抵达出发TrainNumber 等

我知道如何检索特定列车的出发时间,但如果我想根据用户选择的出发站和到达站检索包含多个连接列车的旅行计划,我将如何继续?

如果有人想从伦敦前往曼彻斯特,但没有直达列车沿着这条路线行驶,所以他不得不改变列车我的利物浦。我如何查询数据库以获得此结果?

我希望有人可以帮助我,因为我无法找到解决方案。

6 个答案:

答案 0 :(得分:3)

这不能简化为简单的SQL查询。或者是一个复杂的问题:)

您想要解决Shortest Path Problem

您将需要使用您的工作站作为顶点构建图形,以及表示从一个工作站到另一个工作站的可能旅程的顶点之间的路径(请注意,您将有一个从一个节点到另一个节点的路径,按出发时间键入)。每条路径的重量是它(旅程的)持续时间。

然后使用维基百科链接建议的算法之一来解决最短路径问题,记住您必须在N站等待直到列车到达N + 1站的出发时间。 / p>

听起来像个有趣的黑客!

答案 1 :(得分:3)

确实,在给出完全未知数据的情况下找到问题的最佳解决方案远远超出了SQL的能力。也就是说,从理论上讲,最快的路线可能是带着数千次列车改变的旅程,可能的组合总数远远超出任何计算机的处理能力。

但在实践中,我认为可以肯定地说,火车更换次数减少的行程几乎总是比停靠次数更多的旅行更快,而旅行者可能更愿意在总行程略短的情况下减少火车更换,因为它避免了由于延误,换乘火车的麻烦和错过火车的危险。我不知道你的铁路系统是什么样的(甚至你来自哪里)但是我猜大多数旅行都可以通过适度的火车更换完成,可能很少超过2,对吗?

所以David O'Neill的解决方案基本上是正确的,尽管我认为他给出的查询有点困惑。他没有指定起跑站,他似乎认为整个行程中列车编号没有变化,也许最重要的是,他将时间计算为行程时间的总和。当然对旅行者来说最重要的是出发和到达之间的总时间,而不仅仅是火车上的时间。在火车上十分钟,在车站等候下一班火车四小时,在第二列火车上另外十分钟,是4小时二十分钟,而不是二十分钟。哦,他似乎并没有确保连接列车在第一列火车到达之前不会离开。如果另一列火车在你到达那里之前十分钟离开,那么连接对你没什么好处。

所以我认为真正的查询更像是这样:

哦,你对表格中的内容的描述似乎不完整,所以请原谅我,如果我用自己必须要做的数据创建自己的表格。也就是说,你最好拥有:

Trip (train_number, departure_station_id, arrival_station_id, departure_time, arrival_time)

Station (station_id, station_name) 

首先查询:寻找直接旅行:

select t1.train_number, t1.arrival_time-t1.departure_time as time
from trip t1
where t1.departure_station_id=?station_from
and t1.arrival_station_id=?station_to
order by time

如果没有任何结果,请再次尝试换一次火车:

select t1.train_number, t2.train_number, t2.arrival_time-t1.departure_time as time
from trip t1
join trip t2 on (t2.departure_station_id=t1.arrival_station_id
and t2.departure_time>t1.arrival_time)
where t1.departure_station_id=?station_from
and t2.arrival_station_id=?station_to
order by time

如果仍然没有,请尝试两次火车更换:

select t1.train_number, t2.train_number, t3.train_number, t3.arrival_time-t1.departure_time as time
from trip t1
join trip t2 on (t2.departure_station_id=t1.arrival_station_id
and t2.departure_time>t1.arrival_time)
join trip t3 on (t3.departure_station_id=t2.arrival_station_id
and t3.departure_time>t2.arrival_time)
where t1.departure_station_id=?station_from
and t3.arrival_station_id=?station_to
order by time

您可以将所有这些内容与UNION合并到一个查询中,在较短的查询中填入额外列车编号的空值。这样做的好处是,如果一次额外列车改变的旅行确实更短,那么你会找到一个。但我怀疑很少发生。为了使联合工作,你必须进行最大数量的更改 - 无论你想要什么 - 每次查询,性能都可能很糟糕。

我没有尝试过这个,但我猜想如果使用适当的索引,无变化的查询会很快,一次更改会非常快,两次更改会开始变慢,超出此范围可能是一个非常长的查询,因为可能的组合数量将是巨大的。请注意,像这样的简单查询将包括荒谬的itineries。你想从伦敦去巴黎吗?我们可以尝试伦敦到莫斯科到罗马到巴黎。或伦敦到格拉斯哥回到伦敦,然后到巴黎。当然,这些时间很长,而ORDER BY会将它们排在最底层,但它们会显示出可能必须消除的路线。您可以添加标准来消除自身返回的路线,但其他荒谬的行程更难识别。

玩得开心!

答案 2 :(得分:0)

我对table2中的信息有点不确定。目前,我假设table2包含出发时间和目的地站(dest_station_name)

select t1.station_name, t2.station_name, t3.station_name, 
  t4.station_name, t5.station_name,  
  sum(t2.arrival - t1.departure + /*the rest of them */) as total_time from table2 t1
join table2 t2 on t1.dest_station_name = t2.station_name 
  and t1.train_number = t2.train_number
join table2 t3 on t2.dest_station_name = t3.station_name 
   and t2.train_number = t3.train_number
join table2 t4 on t3.dest_station_name = t4.station_name 
   and t3.train_number = t4.train_number
join table2 t5 on t4.dest_station_name = t5.station_name 
   and t4.train_number = t5.train_number
where t5.station_name = :goal_station
order by total_time desc;

由于你不会提前知道你想要多少跳跃,你可能想写一系列这些跳跃,每个都有不同数量的火车跳跃。运行1跳并查找没有返回的数据。它没有返回任何内容,运行2跳查询。如果没有返回任何内容,请运行3跳查询,依此类推。

编辑格式

注意:正如其他答案和评论中所述:这不能用于保证最短路径。这可用于查找跳数最少的路径。例如,我写的技术建议从纽约到华盛顿特区,从纽约到洛杉矶到华盛顿特区,即使纽约到新泽西州特伦顿到兰彻斯特到华盛顿特区也是如此。

答案 3 :(得分:0)

我怀疑你偶然发现了一些可能没有任何真正答案的特别难题。一个甚至几个查询可能无法实现。假设用户选择A站到B站作为旅程。

  1. 查找从A开始到B结束的所有列车。如果您发现任何列车,则可以停止。
  2. 如果没有找到所有从A开始的列车。
  3. 对于每个站点S1,S2,...,Sn,从A开始的列车查询从Sx到B开始的列车。如果找到列车然后停止。但是,如果不是,你必须重复。此时你必须要小心,你不要在循环中结束。那是你从A - E找到一列火车,然后是E - F,然后是F - A.
  4. 您可能需要使用这样的递归函数(注意,这不是完全考虑过的):

    journey(A, B)
          if A = B then return empty journey else
          query for trains that go from A to B, if found return the one step journey
          else
              query for all trains that start at A
              for each endpoint of trains that start at A => E
                   rest = journey(E, B)
              return A-E+rest
    

答案 4 :(得分:0)

我认为你真的不需要最短路径解决方案。

通常网站都知道城市之间的最多2条火车路线。反正通常都没有。 如果用户想要使用其他路线,那么您有一个“旅行途中”字段。

所以你只需将路线连接成一个。

答案 5 :(得分:0)

我想解决这个问题的方法你需要实现某种搜索算法 - 用简单的查询就无法解决。您应该在结构中加载列车时间,然后查找从A到B的所有可能连接。

当找到给定参数内的所有可能路线时(假设您知道计划行程的日期),您应该按照几个标准对它们进行排序 - 如最短行程,最快行程,最便宜的行程 - 如果您存储机票成本信息,则最少列车开关等数量...然后显示最有利的结果。

听起来像一个有趣的项目可以工作一段时间。你可能已经给了我一个关于周末新爱好项目的想法;)