seek
seek

Reputation: 1105

How to select from database positions where car has been stopped?

I have a MySQL table with data from car GPS tracker (lat, lng, speed, time). I want to select positions (latitude, longitude and time) where car has been stopped (speed = 0) longer than 10 min, 30 min, 1 hour etc.

My table looks like this:

id  latitude            longitude           speed   time
-----------------------------------------------------------------------
304 52.388983333333336  17.025338333333334  33.67   2014-03-26 08:00:04
305 52.39029            17.023776666666667  34.65   2014-03-26 08:00:14
306 52.391035           17.021631666666668  32.91   2014-03-26 08:00:24
307 52.39103166666666   17.01917            30.03   2014-03-26 08:00:34
308 52.39089833333333   17.01698            29.33   2014-03-26 08:00:44
309 52.390593333333335  17.01532            9.54    2014-03-26 08:00:54
310 52.39071333333333   17.015056666666666  0       2014-03-26 08:01:04
311 52.39105333333333   17.01499            10.3    2014-03-26 08:01:14
312 52.391485           17.01488            7.82    2014-03-26 08:01:24
313 52.391705           17.014815           0       2014-03-26 08:01:34
314 52.391705           17.014815           0       2014-03-26 08:01:44
315 52.391705           17.014815           0       2014-03-26 08:01:54
316 52.391705           17.014815           0       2014-03-26 08:02:04
317 52.391705           17.014815           0       2014-03-26 08:02:14
318 52.391705           17.014815           0       2014-03-26 08:02:24
319 52.39232333333333   17.014648333333334  7.12    2014-03-26 08:02:34
320 52.392345           17.014635           0       2014-03-26 08:02:44
321 52.392345           17.014635           0       2014-03-26 08:02:54
322 52.392345           17.014635           0       2014-03-26 08:03:04
323 52.392345           17.014635           0       2014-03-26 08:03:15
324 52.392345           17.014635           0       2014-03-26 08:03:25
325 52.392345           17.014635           0       2014-03-26 08:03:35
326 52.392558333333334  17.014471666666665  14.11   2014-03-26 08:03:45
327 52.392316666666666  17.012883333333335  27.47   2014-03-26 08:03:55
328 52.39194333333333   17.010871666666667  28.93   2014-03-26 08:04:05
329 52.39152333333333   17.00893            22.28   2014-03-26 08:04:15
330 52.391575           17.007181666666668  27.01   2014-03-26 08:04:25
331 52.39164            17.00501            26.48   2014-03-26 08:04:35
332 52.39159333333333   17.002895           28.34   2014-03-26 08:04:45
333 52.391641666666665  17.000795           26.39   2014-03-26 08:04:55
334 52.392156666666665  16.999178333333333  16.56   2014-03-26 08:05:05
335 52.39223666666667   16.998796666666667  0       2014-03-26 08:05:15
336 52.39234            16.99819            15.38   2014-03-26 08:05:25
337 52.39261166666667   16.996865           17.1    2014-03-26 08:05:35
338 52.392896666666665  16.995643333333334  20.91   2014-03-26 08:05:45
339 52.39313666666666   16.99468            7.5     2014-03-26 08:05:55
340 52.39331833333333   16.993918333333333  9.1     2014-03-26 08:06:05
341 52.3936             16.992806666666667  16.86   2014-03-26 08:06:15
342 52.393746666666665  16.992065           4.72    2014-03-26 08:06:25

I have a MySQL query that should do this, but it kills my database.

select speed, latitude, longitude, min(time) as StartTime, max(time) as EndTime
from (select t.*,
    (select count(*)
    from positions t2
    where t2.time  0
    ) as grp
    from positions t
    ) t
    where time >= '$from' AND time = min(time) + interval 1 minute

I'm looking for other ideas how to find this positions with speed 0 and idle time.

For example:

Speed: 0
StartTime: 2014-03-26 08:01:34
EndTime: 2014-03-26 08:02:24

Looking for help, any ideas?

Upvotes: 1

Views: 530

Answers (1)

FuzzyTree
FuzzyTree

Reputation: 32402

This selects positions that have been idle more than 10 minutes. The inner query selects all positions and idle times and the outer query filters by the minimum idle time. For the inner query an idle car will have a speed of 0 and at least 2 rows at the same position. The idle time is calculated by taking the difference between the maximum and minimum times at the same position.

SELECT * FROM 
    (SELECT
        latitude,
        longitude,
        TIME_TO_SEC(TIMEDIFF(MAX(time),MIN(time))) idle_time
    FROM positions
    WHERE speed = 0
    GROUP BY latitude, longitude
    HAVING COUNT(*) > 1) t
WHERE idle_time > 600

As pointed out in the comments, the query above assumes that a vehicle will never return to the same position. If it's possible for a vehicle to return to the same position, we need to make sure that the grouped positions are consecutive. This is done in the query below by verifying that the car has not been at another position between the max and min times used for each grouping.

Not tested

SELECT * FROM 
    (SELECT
        latitude,
        longitude,
        TIME_TO_SEC(TIMEDIFF(max_time,min_time)) idle_time
    FROM (SELECT
        latitude,
        longitude,
        (SELECT MIN(time) 
            FROM positions p2 
            WHERE p2.latitude = p1.latitude
            AND p1.longitude = p2.longitude
            AND NOT EXISTS (SELECT 1 FROM positions p3 
            WHERE p3.time < p1.time AND p3.time > p2.time
            AND (p3.longitude != p2.longitude OR p3.latitude != p2.latitude))
        ) min_time,
        (SELECT MAX(time) 
            FROM positions p2 
            WHERE p2.latitude = p1.latitude
            AND p2.longitude = p1.longitude
            AND NOT EXISTS (SELECT 1 FROM positions p3 
            WHERE p3.time > p1.time AND p3.time < p2.time
            AND (p3.longitude != p2.longitude OR p3.latitude != p2.latitude))
        ) max_time
     FROM positions p1
     WHERE speed = 0) 
    GROUP BY latitude, longitude, min_time, max_time
    HAVING COUNT(*) > 1) t
WHERE idle_time > 600

Upvotes: 3

Related Questions