我有一张表格,描述了公交车站的封闭路径,以及沿路径行驶的公交车:
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
注意事项:
- stop_id 是唯一的
- order_in_route 是独一无二的
- time_from_last_stop 不是唯一的
- bus_id 是唯一的(除非为 NULL)
- 该表必须包含至少 1 个 NON-NULL bus_id
这基本上意味着路径的每个循环都穿过每个停靠点一次且仅一次,并且每个停靠点在 route 都有其独特的顺序。最后,在任何给定时间至少有 1 辆公共(public)汽车沿着路线行驶,如果有多辆公共(public)汽车在行驶,它们是唯一的,并且永远不会同时停在同一站。
在这种情况下,循环路径将是(在 -> 中注明每个站点之间的时间):
... stop 9 -5> stop 3 -10> stop 6 -5> stop 2 -15> stop 1 -10> stop 9 -5> stop 3...
目前3号站和1号站都有公交车,所以公交车到达这2个站的时间为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 相加,直到您到达当前有公共(public)汽车停靠的站点。此外,要计算到达它的公交车,您会找到离您最近的公交车。
第 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
所以决赛 table 应该是:
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 中的语句。
到目前为止我尝试过的是(#'s note commented code that I do not know how to structure):
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;
这显然是不正确的语法,但我认为这个想法很清楚。
最佳答案
这是 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 中,我们使用公用表表达式之类的东西来实现这种功能分解)。
关于mysql - 根据行有条件地对列中的值求和,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47465898/