我相信这是正确的(请参阅SQL Fiddle来测试它):
SELECT
s1.id AS stopped_row_id, MIN(s2.id) AS departed_row_id, TIMESTAMPDIFF(SECOND, s1.timestamp, MIN(s2.timestamp)) AS stopped_seconds
FROM
stops AS s1
JOIN stops AS s2 ON
s1.imei = s2.imei
AND s1.id < s2.id
AND (s1.timestamp + INTERVAL 4 MINUTE) <= s2.timestamp
JOIN stops AS s3 ON
s1.imei = s2.imei
AND s3.id = s1.id - 1
LEFT JOIN stops AS s4 ON
s1.imei = s2.imei
AND s4.id BETWEEN (s1.id + 1) AND (s2.id - 1)
AND s4.speed <> 0
WHERE
s1.speed = 0
AND s2.speed <> 0
AND s3.speed <> 0
AND s4.id IS NULL
AND s1.imei = 7466 -- optional; query will also give results for all imei if wanted
AND s1.timestamp BETWEEN '2013-08-20 00:00:00' AND '2013-08-20 23:59:59' -- optional, query will give results for entire table if wanted
GROUP BY
s1.id,
s1.timestamp
在此查询中,s1
是“主”表。
s2
连接以向所有行提供比id
s 高至少 4 分钟的所有行(因此本质上,所有行都指示暂停的时间足够长,以使行 from应该进入最终结果集)。连接以确保其中的行是 0的第一行(对于您的示例,其中有0 组的行)。连接以确保在 和 的“选定”行之间没有非零速行。确保我们可以在未来获得
第一个时间戳s1
timestamp
s1
s2
s1
s3
s1
speed
speed
s4
s1
s2
GROUP BY
speed
通过使用 不为 0 MIN()
。
显然,这些行不是严格的降序或升序(即使 ID 是)。我已经修改了查询,只使用时间作为“排序机制”。请注意,这会使查询变得非常慢,您可能会更好地通过以@peterm 的样式排序表或解决方案。或者至少在id
and上添加一个索引timestamp
。
SELECT
s1.timestamp AS stopped_timestamp, MAX(s2.timestamp) as departed_timestamp, TIMESTAMPDIFF(SECOND, s1.timestamp, MAX(s2.timestamp)) AS stopped_seconds
FROM
stops AS s1
JOIN stops AS s2 ON
s1.imei = s2.imei
AND (s1.timestamp + INTERVAL 4 MINUTE) <= s2.timestamp
JOIN stops AS s3 ON
s1.imei = s2.imei
LEFT JOIN stops AS s4 ON
s1.imei = s2.imei
AND s4.timestamp BETWEEN (s1.timestamp + INTERVAL 1 SECOND) AND (s2.timestamp - INTERVAL 1 SECOND)
AND s4.speed <> 0
WHERE
s1.speed = 0
AND s2.speed <> 0
AND s3.speed <> 0
AND s4.id IS NULL
AND s1.imei = 7466 -- optional; query will also give results for all imei if wanted
AND s1.timestamp BETWEEN '2013-08-20 00:00:00' AND '2013-08-20 23:59:59' -- optional, query will give results for entire table if wanted
AND s3.timestamp = (SELECT MAX(s5.timestamp) FROM stops AS s5 WHERE s5.timestamp < s1.timestamp)
GROUP BY
s1.id,
s1.timestamp