基于行

时间:2017-11-24 03:23:51

标签: mysql sql

我有一张表格描述了公共汽车站的封闭路径,以及沿着小路行驶的公共汽车:

stop_id | order_in_route | time_from_last_stop | bus_id
------------------------------------------------------
3       | 1              | 5                   | 3
6       | 2              | 10                  | NULL
2       | 3              | 5                   | NULL
1       | 4              | 15                  | 2
9       | 5              | 10                  | NULL

注意事项:

  1. stop_id是唯一的
  2. order_in_route是唯一的
  3. time_from_last_stop不是唯一的
  4. bus_id是唯一的(除非为NULL)
  5. 该表必须包含至少1个NON-NULL bus_id
  6. 这基本上意味着路径的每个循环都会跨越每个停靠点一次且仅一次,并且每个停靠点在路径中都有自己独特的顺序。最后,在任何给定时间沿着这条路线至少有一辆公共汽车,如果有多辆公共汽车在行驶,它们是独一无二的,并且不会同时停在同一站。

    在这种情况下,圆形路径(在每个停止点之间的时间记录在 - >内):

    ... stop 9 -5> stop 3 -10> stop 6 -5> stop 2 -15> stop 1 -10> stop 9 -5> stop 3...
    

    目前,在3号站和1号站有一辆公共汽车。因此,公共汽车到达这两站的时间是0,到达每站的公共汽车是目前的公共汽车:

    stop_id | order_in_route | time_for_bus_to_arrive | bus_id
    -----------------------------------------------------------
    3       | 1              | 0                      | 3
    1       | 4              | 0                      | 2
    

    要计算一辆公共汽车在没有当前公交车的情况下到达每个站点的时间,请为自己和你后面的每个站点总结 time_from_last_stop ,而不是当前在公交车站,直到你到达目前停在公交车站。此外,要计算到达它的公交车,你会发现最近的公交车。

    对于第6站:

    time_for_a_bus_to_arrive(stop 6) = time_from_last_stop(stop 6)
                                     = 10
    bus_id(stop 6) = 3
    

    对于第2站:

    time_for_a_bus_to_arrive(stop 2) = time_from_last_stop(stop 2) + time_from_last_stop(stop 6)
                                     = 5 + 10
                                     = 15
    bus_id(stop 2) = 3
    

    对于第9站:

    time_for_a_bus_to_arrive(stop 9) = time_from_last_stop(stop 9)
                                     = 10
    bus_id(stop 9) = 2
    

    所以决赛桌应该是:

    stop_id | order_in_route | time_for_bus_to_arrive | bus_id
    ------------------------------------------------------
    3       | 1              | 0                      | 3
    6       | 2              | 10                     | 3
    2       | 3              | 15                     | 3
    1       | 4              | 0                      | 2
    9       | 5              | 5                      | 2
    

    我的问题是如何在MySQL中使用单个SELECT查询来实现这一目标?我不知道如何在MySQL中的语句中实现上面的人类可读逻辑。

    我到目前为止所尝试的是(#注释注释的代码,我不知道如何构建):

    SELECT stop_id, order_in_route, SUM(time_from_last_stop
      WHERE bus_id IS NULL # AND order_in_route is earlier in path AND is after a bus_id that is NOT NULL
    ) AS time_for_bus_to_arrive, (SELECT bus_id
      FROM firstTable
      WHERE bus_id IS NOT NULL # AND closest behind in path
    ) AS bus_id
    FROM firstTable;
    

    这显然是不合适的语法,但我认为这个想法很明确。

1 个答案:

答案 0 :(得分:0)

这是SQL Server语法,利用窗口函数(我复制了你的表并获得了你正在寻找的结果),但我认为MySQL中有类似的语法:

SELECT stop_id, 
       order_in_route, 
       next_bus, 
       arrival_time
FROM (SELECT Stops.stop_id, Stops.order_in_route, tA.next_bus, tA.prev_order_in_route,
             SUM(CASE WHEN Stops.bus_id IS NULL THEN Stops.time_from_last_stop ELSE 0 END) OVER (PARTITION BY tA.prev_order_in_route ORDER BY Stops.order_in_route) AS arrival_time,
             MAX(tA.prev_order_in_route) OVER (PARTITION BY Stops.order_in_route ORDER BY Stops.order_in_route) AS max_prev_order_in_route
      FROM Stops LEFT JOIN (SELECT order_in_route AS prev_order_in_route, bus_id AS next_bus 
                            FROM Stops 
                            WHERE bus_id IS NOT NULL) tA ON tA.prev_order_in_route <= Stops.order_in_route ) tB 
WHERE prev_order_in_route = max_prev_order_in_route         
ORDER BY order_in_route

在此过程中,重要的是为每个停靠点计算下一班车停靠的order_in_route是什么。我称之为prev_order_in_route。例如,前三站prev_order_in_route = 1,最后两站prev_order_in_route = 4。当这个数字变化时,我们知道我们已经遇到了一个有总线的停止,因此我们需要重置SUM()函数来计算下一个总线的到达时间。

除非有一些巨大的性能提升,否则我可能会尽可能避免在SQL中执行所有这些操作(例如,如果这是针对智能手机应用程序,则可以通过服务器端代码更加透明地完成此处理或网站)。

如果在SQL中执行它是必要的,那么将其分解为单独的部分,以使它看起来不像一团糟(在SQL Server中,我们使用公共表表达式之类的东西来实现这种功能分解)。