This is assuming that each user can only be joined once to a conversation:
SELECT c.*
FROM conversations c
JOIN notifications n1 ON n1.conversation_id = c.id
JOIN notifications n2 ON n2.conversation_id = c.id
WHERE n1.user_id = 1
AND n2.user_id = 2
AND NOT EXISTS (
SELECT 1
FROM notifications n3
WHERE n3.conversation_id = c.id
AND n3.user_id <> ALL ('{1,2}')
)
This is a special case of relational division. We have assembled a whole arsenal of techniques under this this related question:
How to filter SQL results in a has-many-through relation
The special requirement is to exclude additional matches. I use NOT EXISTS
for this end. You could also use LEFT JOIN / IS NULL
or NOT IN
. More details here:
Select rows which are not present in other table
There could be several notifications for the same user
To avoid duplicate conversations in the result you can use DISTINCT
or GROUP BY
in addition to the above. Or you suppress duplicates to begin with (probably faster):
SELECT c.*
FROM conversations c
WHERE EXISTS (
SELECT 1
FROM notifications n1
JOIN notifications n2 USING (conversation_id)
WHERE n1.conversation_id = c.id
AND n1.user_id = 1
AND n2.user_id = 2
)
AND NOT EXISTS (
SELECT 1
FROM notifications n3
WHERE n3.conversation_id = c.id
AND n3.user_id <> ALL ('{1,2}')
)