views:

49

answers:

2

Currently I am performing a left join on two tables. The first table has an id and a persons name, the second table has an id, the id of a person from table 1, and then a timestamp (of a flight).

People                             Flights
id   |  name             id   |   person_id   | time
------------             ---------------------------
1       Dave              1         1          1284762115
2       Becky             2         1          1284787352
                          3         2          1284772629
                          4         2          1286432934
                          5         1          1283239480

When I perform my left join, I get a list of people and their flight times, but what I would like is just the list of people with the flight time with the highest ID

I have been using

   SELECT p.id, p.name max(f.time) 
     FROM People p 
LEFT JOIN Flights f ON p.id = f.person_id
 GROUP BY p.id, p.name

However, this just gives me the LAST flight time, rather than the last flight time uploaded into the system (ie, highest ID).

1 Dave  1284787352
2 Becky 1286432934

So to reiterate, I would like to see the name of the person, along with the flight time of their last UPLOADED (highest ID) flight time.

1 Dave  1283239480
2 Becky 1286432934
+5  A: 

Use:

SELECT p.id,
       p.name,
       f.time
  FROM PEOPLE p
  JOIN FLIGHTS f ON f.person_id = p.id
  JOIN (SELECT f.person_id,
               MAX(f.id) AS max_id
          FROM FLIGHTS f
      GROUP BY f.person_id) x ON x.person_id = f.person_id
                             AND x.max_id = f.id

If you are using a database that supports analytics:

SELECT p.id,
       p.name,
       x.time
  FROM PEOPLE p
  JOIN (SELECT f.person_id,
               f.time,
               ROW_NUMBER() OVER(PARTITION BY f.person_id
                                     ORDER BY f.id DESC) AS rk
          FROM FLIGHTS f) x ON x.person_id = p.id
                           AND x.rk = 1

If you want people, including those without flights:

   SELECT p.id,
          p.name,
          f.time
     FROM PEOPLE p
LEFT JOIN FLIGHTS f ON f.person_id = p.id
     JOIN (SELECT f.person_id,
                  MAX(f.id) AS max_id
             FROM FLIGHTS f
         GROUP BY f.person_id) x ON x.person_id = f.person_id
                                AND x.max_id = f.id

...and the analytic version:

   SELECT p.id,
          p.name,
          x.time
     FROM PEOPLE p
LEFT JOIN (SELECT f.person_id,
                  f.time,
                  ROW_NUMBER() OVER(PARTITION BY f.person_id
                                        ORDER BY f.id DESC) AS rk
             FROM FLIGHTS f) x ON x.person_id = p.id
                              AND x.rk = 1
OMG Ponies
Right on the money! Thanks Ponies, I wasn't even close with what I had =(
Nick Brown
This will drop out anyone who doesn't have a flight; use a left join rather than inner per his original query
Tahbaza
Ah, for my particular use -this- time I want to drop out anyone without a flight time, however, in the future this may not be the case. In that instance, you are saying change both joins to Left joins?
Nick Brown
@Nick Brown: See update
OMG Ponies
Thanks again, Ponies!
Nick Brown
+1  A: 

I think you are looking for something like the below. group by the person_id and select the max id then use that list to select from the flights. This is my first thought there may be a more efficent way.

EDITED:

SELECT p.id, p.name max(f.time)
FROM People p
LEFT JOIN Flights f ON p.id = f.person_id where f.id in(select max(id) from flights group by person_id)

BitOff
#1052 - Column 'id' in IN/ALL/ANY subquery is ambiguous
Nick Brown
sorry, see edit.
BitOff