Reputation: 4147
I have done a fair amount of googling, but I can't seem to get this one right..
I have three tables:
comm_messages:
- room_id:integer
- created_at:datetime
comm_visitors:
- room_id:integer
- user_id:integer
- updated_at:datetime
I want to find out for a given user_id, how many new messages (the ones that were created after the user visited the room) are there?
If I have this kind of data:
comm_messages:
+---------+------------------+
| room_id | created_at |
+---------+------------------+
| 1 | 20.11.2018 |
| 1 | 20.12.2018 |
| 2 | 21.12.2018 |
| 3 | 24.12.2018 |
| 4 | 19.05.2018 |
+---------+------------------+
comm_visitors:
+---------+---------+------------+
| user_id | room_id | updated_at |
+---------+---------+------------+
| 1 | 1 | 03.11.2018 |
| 1 | 3 | 25.12.2018 |
| 1 | 4 | 11.05.2018 |
| 2 | 1 | 01.01.2019 |
| 2 | 2 | 03.11.2018 |
| 2 | 4 | 03.11.2018 |
+---------+---------+------------+
For user_id = 1
I should get 3
and for user_id = 2
I should get 2
.
My current attempt has been revolving around something like this:
SELECT COUNT(comm_messages.id)
FROM comm_messages LEFT JOIN comm_visitors
ON comm_messages.room_id = comm_visitors.room_id
WHERE comm_visitors.user_id = 1
AND comm_visitors.updated_at > comm_messages.updated_at;
But that's no good..
Upvotes: 0
Views: 90
Reputation: 2161
You're very close, but to get the unread messages you need to look for messages created after / "greater than" the user's visit time, like so:
select count(1)
from comm_visitors v
join comm_messages m on v.room_id = m.room_id
--only include messages created _after_ the last visit
and v.updated_at < m.created_at
where v.user_id = 1
If you want to include messages in rooms the user has never visited as unread, you can use something like:
select count(1)
from comm_messages m
left join comm_visitors v on v.room_id = m.room_id and v.user_id = 1
where m.created_at > coalesce(v.updated_at, '1900-01-01')
Upvotes: 1
Reputation: 1271161
I think you are pretty close. This should do what you want:
SELECT COUNT(*)
FROM (SELECT v.user_id, v.room_id, MAX(v.updated_at) as last_visit
FROM comm_visitors v
WHERE v.user_id = 1
GROUP BY v.user_id, v.room_id
) v JOIN
comm_messages m
ON m.room_id = v.room_id AND
v.last_visit > m.updated_at;
EDIT:
Based on the comment, you should be able to do:
SELECT COUNT(*)
FROM comm_visitors v JOIN
comm_messages m
ON m.room_id = v.room_id AND
v.updated_at > m.updated_at
WHERE v.user_id = 1
Upvotes: 1