1

次の select ステートメントを使用して、トラックがある場所で停止してからの時間を知るためにタイムスタンプを減算します。

 SELECT  f.id, f.imei as imei, f.speed as speed  FROM stops f, stops f2
 where f2.id = f.id-1
 and f.imei = 7466
 and hour(timediff(f2.timestamp,f.timestamp)) * 3600 +   minute(timediff(f2.timestamp,f.timestamp)) * 60 + second(timediff(f2.timestamp,f.timestamp)) > 240 
 and f.speed = 0
 and f2.timestamp >= '2013-08-20 00:00:00' 
 and f2.timestamp <= '2013-08-20 23:59:59'  
 order by f2.timestamp desc

ストップを計算するための行:

id imei     timestamp               speed
1  7466     2013-08-20 13:19:00     30    
2  7466     2013-08-20 13:20:00     0 
3  7466     2013-08-20 13:24:30     20

そのため、select は、車両 7466 に 4 分間の停止があったことを結果として示します。

行が次のような場合に問題が発生します。

id imei     timestamp               speed 
1  7466     2013-08-20 13:19:00     30     
2  7466     2013-08-20 13:20:00     0 
3  7466     2013-08-20 13:21:00     0 
4  7466     2013-08-20 13:22:00     0 
5  7466     2013-08-20 13:24:30     20

引き算はしません。結果の時間を取得するにはどうすればよいですか?

4

3 に答える 3

1

I believe this is correct (see the SQL Fiddle to test it):

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

In this query, s1 is the 'main' table.
s2 is joined to provide all rows with higher ids than that of s1 where the timestamp is at least 4 minutes higher than that of s1 (so in essence s2 is all rows indicating pauses long enough that the row from s1 should go into the final result set).
s3 is joined to make sure that the row in s1 is the first row where speed is 0 (for your example where there are sets of rows where speed is 0).
s4 is joined to make sure that there are no non-zero-speed rows between the 'selected' rows from s1 and s2.
The GROUP BY makes sure that we can get the first timestamp in the future where speed is not 0 by using MIN().


Apparently, the rows are not in a strict descending or ascending order (even if the IDs are). I have reworked the query to only use the time as 'sorting mechanism'. Note that this makes the query very slow, and you might be better off by ordering the table or a solution in the style of that of @peterm. Or at least adding an index on id andtimestamp.

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
于 2013-08-20T00:22:31.623 に答える
0

4 分 (240 秒) 以上停止しているトラックを求めています。SQL クエリの次の行を参照してください。

hour(timediff(f2.timestamp,f.timestamp)) * 3600 + 
minute(timediff(f2.timestamp,f.timestamp)) * 60 + 
second(timediff(f2.timestamp,f.timestamp)) > 240

次の表では...

id imei     timestamp               speed     
1  7466     2013-08-20 13:20:00     0 
2  7466     2013-08-20 13:21:00     0 
3  7466     2013-08-20 13:22:00     0 
2  7466     2013-08-20 13:24:00     20

これらのペアのいずれにおいても、トラックが 4 分 (240 秒) を超えて停止していません。これらのペアは WHERE 条件を満たさないため、選択されません。

于 2013-08-19T23:47:56.380 に答える
0

UPDATEDそれを行う1つの方法

SELECT duration / 60 duration
  FROM
(
  SELECT id, imei, timestamp, speed, 
         @d := IF(@s = 0 AND speed > 0, 
                  @d := @d + TIMESTAMPDIFF(SECOND, @t, timestamp),
                  @d) duration, 
         @t := IF(@s = 0 AND speed = 0, @t, timestamp),
         @s := speed 
    FROM stops, (SELECT @d := 0, @s := -1, @t = 0) i
   WHERE imei = 7466
     AND timestamp >= '2013-08-20 00:00:00' AND timestamp <= '2013-08-20 23:59:59' 
   ORDER BY timestamp
 ) z
 ORDER BY timestamp DESC
 LIMIT 1

出力:

+---------+
| | 期間 |
+---------+
| | 4 |
+---------+

これがSQLFiddleのデモです

于 2013-08-20T00:12:01.707 に答える