Ciaran Fisher
Ciaran Fisher

Reputation: 1006

Selecting top result from SQL

This is i think a simple problem but i can't seem to solve it.

I want to select the newest result from a table and join it with a single element in another table.

To put it better, here's a simple schema:

Table 1 - Person
personId -PK - INT - AUTO ID
name - VARCHAR

Table 2 - Event
eventId - PK - INT - AUTO ID
personId - FK
timestamp  - DATETIME
event - ENUM ('Went Out', 'Came back')

What I'd like to do is return a list of all people and the latest action each person performed

Example Result:

name| personId | timestamp | eventId | event

bob | 1 | 2011-08-7 3 | 'went out'

I did a simple query joining the two tables and then did a group by personId and order by timestamp but the result that was returned was always the first action for the person, not their latest.

Any Ideas?

Upvotes: 1

Views: 257

Answers (5)

sll
sll

Reputation: 62504

SELECT p.name, p.personId, e.timestamp, e.eventId, e.event
FROM person p
  INNER JOIN Event e 
    ON e.eventId = 
      ( SELECT MAX(eventId)
        FROM Event 
        WHERE personId = p.personId 
        GROUP BY personId 
        LIMIT 1 )

OR

SELECT p.Name, p.ID, me.timestamp, me.ID, me.event
FROM person p
INNER JOIN (
            SELECT id, timestamp, event
            FROM Event 
            WHERE personId = p.ID               
            ORDER BY timestamp DESC LIMIT 1
           ) me
ON p.ID = me.id

PS: sorry but can't test both queries right now

Upvotes: 3

Hugh Jones
Hugh Jones

Reputation: 2694

An alternative solution, making use of a covered key, assumes that order by Id would yield the same results as order by timestamp

SELECT p.Name, p.ID, me.timestamp, me.ID, me.event
FROM person p
JOIN (
      SELECT personId, MAX(ID) id 
      FROM Event 
      WHERE personId = p.ID               
      GROUP BY personId
     ) me
ON p.ID = me.id

Order by timestamp is more natural and probably safer, but this is quicker.

Upvotes: 0

Jay
Jay

Reputation: 27474

The ANSI standard way would be:

select name, personid, timestamp, eventid, event
from person
join event on event.personid=person.personid
  and event.timestamp=(select max(timestamp) from event e2
                       where e2.personid=person.personid)

I haven't used MySQL in a while and I don't have an installation handy, but you might get what you want with:

select name, personid, timestamp, eventid, event
from person
join event on event.personid=person.personid
group by personid
order by personid, timestamp desc

It's non-standard because by the standard, anything in the select must be in the group-by or be an aggregate, and here we don't want to do either. But as I recall MySQL doesn't require that, so I'd give this a whirl and see what happens.

Upvotes: 0

John Hartsock
John Hartsock

Reputation: 86882

SELECT 
  t1.Name,
  t1.PersonId,
  t2.TimeStamp,
  t2.EventId,
  t2.Event
FROM Table1 t1
INNER JOIN Table2 t2 ON t2.PersonId = t1.PersonID
INNER JOIN (SELECT
              PersonId,
              MAX(TimeStamp) as LastEventDateTime
            FROM Table2 
            GROUP BY PersonID) LE 
  ON LE.PersonID = t2.PersonID 
    AND LE.LastEventDateTime = t2.TimeStamp

Upvotes: 3

Nanne
Nanne

Reputation: 64399

you'd want to do an

ORDER by `timestamp` DESC

(desc from descending) to get the highest timestamp value instead of the lowest

Upvotes: 0

Related Questions