mysql - 根据行有条件地对列中的值求和

标签 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

这基本上意味着路径的每个循环都穿过每个停靠点一次且仅一次,并且每个停靠点在 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/

相关文章:

php - 如何编写 Laravel Eloquent whereBetween 方法与两列

php - Mysql:计算有多少行有一个或多个特定关键字

java - 如何在android中使用契约(Contract)类?

SQL 过滤索引 : should I always put a filter on an index for optional columns?

c# - 尽管有查询字符串,但在使用 sql COUNT 时 ExecuteNonQuery 返回 -1

python - 为什么列的默认值不适用于 django

mysql - 在sql上写查询

MYSQL - 按另一个表对一个表进行排序

mysql - 使用 mySQL 查找今天的免费房间

mysql - 在触发条件中插入 null 和字符串 'Null