Reputation: 27852
I have two tables:
User (id, name)
UserEvent (id, user_id, name, date)
How can I get all the users where the last (ordered by date) UserEvent.name
has a value of 'played'?
I wrote an example on SQLFiddle with some specific data: http://sqlfiddle.com/#!9/b76e24 - For this scenario I would just get 'Mery' from table User
, because even though 'John' has associated events name of the last one is not 'played'.
Upvotes: 0
Views: 72
Reputation: 656291
This is probably fastest:
SELECT u.*
FROM usr u -- avoiding "User" as table name
JOIN LATERAL (
SELECT name
FROM userevent
WHERE user_id = u.id
ORDER BY date DESC NULLS LAST
LIMIT 1
) ue ON ue.name = 'played';
LATERAL
requires Postgres 9.3+:
Or you could use DISTINCT ON
(faster for few rows per user):
SELECT u.*
FROM usr u -- avoiding "User" as table name
JOIN (
SELECT DISTINCT ON (user_id)
user_id, name
FROM userevent
ORDER BY user_id, date DESC NULLS LAST
) ue ON ue.user_id = u.id
AND ue.name = 'played';
Details for DISTINCT ON
:
SQL Fiddle with valid test case.
If date
is defined NOT NULL
, you don't need NULLS LAST
. (Neither in the index below.)
Key to read performance for both but especially the first query is a matching multicolumn index:
CREATE INDEX userevent_foo_idx ON userevent (user_id, date DESC NULLS LAST, name);
Aside: Never use reserved words as identifiers.
Upvotes: 1
Reputation: 15057
Here it is:
First i get the MAX ID from each user and join it to the ROW with this ID to test if the status are 'played' if so, i get the username of them.
SELECT
ids.*,
u.name,
ue.*
FROM (
SELECt max(id) AS id from UserEvent
GROUP by user_id
) as ids
LEFT JOIN UserEvent ue ON ue.id = ids.id
LEFT JOIN User u ON u.id = ue.user_id
WHERE ue.name = 'played';
Upvotes: 0
Reputation: 507
Return the max date from user event grouping by user id. Take that result set and join it back to user event by the user id and max date and filter for just the played records.
Upvotes: 0