0

I have a mySQL database to store position information of bikes. For the 'last position' method I want to get only the last entry of a bike but from all bikes.

Example:

ID | ## LAT ## | ## LNG ## | #### TIMESTAMP #### | BIKE_ID
----------------------------------------------------------
16 | N47.68526 | E16.59032 | 2015-01-12 14:49:51 | 3
17 | N47.36345 | E16.12096 | 2015-01-12 14:50:27 | 9
18 | N44.12526 | E15.12562 | 2015-01-12 14:51:45 | 1
19 | N47.87654 | E16.54323 | 2015-01-12 14:51:51 | 3
20 | N47.12345 | E16.12341 | 2015-01-12 14:52:27 | 1
21 | N47.12531 | E15.12561 | 2015-01-12 14:52:45 | 9
22 | N44.12531 | E16.12561 | 2015-01-12 14:53:01 | 1
23 | N47.12531 | E15.12561 | 2015-01-12 14:53:18 | 9
...

I want an output like:

ID | ## LAT ## | ## LNG ## | #### TIMESTAMP #### | BIKE_ID
----------------------------------------------------------
19 | N47.87654 | E16.54323 | 2015-01-12 14:51:51 | 3
22 | N44.12531 | E16.12561 | 2015-01-12 14:53:01 | 1
23 | N47.12531 | E15.12561 | 2015-01-12 14:53:18 | 9
tom_tom
  • 465
  • 1
  • 7
  • 18
  • Check [this answer](http://stackoverflow.com/questions/27183964/sql-sorting-does-not-follow-group-by-statement-always-uses-primary-key/27184343#27184343), [this one](http://stackoverflow.com/questions/27801243/how-to-select-a-row-with-maximum-value-for-a-column-in-mysql/27801835#27801835), [this one](http://stackoverflow.com/questions/27036210/sql-select-first-column-and-for-each-row-select-unique-id-and-the-last-date/27036920#27036920) and [this one](http://stackoverflow.com/questions/612231/how-can-i-select-rows-with-maxcolumn-value-distinct-by-another-column-in-sql/27802817#27802817). – axiac Jan 13 '15 at 14:37
  • I bet this is the most asked `MySQL` question on SO. – axiac Jan 13 '15 at 14:38
  • possible duplicate of [Retrieving the last record in each group](http://stackoverflow.com/questions/1313120/retrieving-the-last-record-in-each-group) – Pᴇʜ Jan 13 '15 at 14:42
  • @axiac: it's so popular it even has its own tag –  Jan 13 '15 at 15:01

3 Answers3

2

1st get a set of data with the the max timestamp for each bike, then join it back to the whole set based on bike id and the max timestamp. This is assuming you need additional data from the base table. If you don't the inner select alone would work...

If you need additional data from table...

SELECT t.id AS 'ID', 
       t.lat AS '## LAT ##', 
       t.lng AS '## LNG ##', 
       t.timestamp AS '#### TIMESTAMP ####', 
       t.bike_Id AS 'BIKE_ID' 
FROM table_Name t
INNER JOIN (SELECT bike_ID, max(timestamp) mts 
            FROM tableName
            GROUP BY bike_ID) t2 
  on t2.bike_ID = t.bike_ID 
 and t2.mts = t.timestamp

If not... Just use an aggregate...

SELECT bike_ID, 
       max(timestamp) mts 
FROM tableName
GROUP BY bike_ID
xQbert
  • 34,733
  • 2
  • 41
  • 62
0

Basically this:

SELECT * 
FROM yourtable
INNER JOIN (
   SELECT BIKE_ID, MAX(TIMESTAMP)
   FROM yourtable
   GROUP BY BIKE_ID
) AS foo ON ((yourtable.BIKE_ID = foo.BIKE_ID) AND (yourtable.TIMESTAMP = foo.TIMESTAMP))

The subquery gets the highest timestamp for every bike ID, which you then use to self-join against the original table to select the other fields which correspond to those id/timestamps.

Marc B
  • 356,200
  • 43
  • 426
  • 500
0

This problem is fairly common, and has an elegant optimization. If your last entry is guaranteed to be the one with the highest value of id (that is, if your id column is an autoincrement column and the table is logging new data), do this:

 SELECT t.BIKE_ID, t.LAT, t.LNG, t.`TIMESTAMP`
   FROM table t
   JOIN (SELECT MAX(ID) AS ID 
          FROM table
         GROUP BY BIKE_ID
        ) m ON t.ID = m.ID

The inner query (MAX ... GROUP BY) efficiently identifies the most recent entry for each bike. If you put the compound index (BIKE_ID, ID) on your table, this query will be very efficient indeed, because it can do a so-called loose index scan.

Pro tip. Make your latitudes and longitudes into FLOAT values, where North and East are positive numbers.

O. Jones
  • 103,626
  • 17
  • 118
  • 172