Assuming you have a users
table as well:
SELECT id
FROM conversations AS c
WHERE NOT EXISTS
( SELECT *
FROM users AS u
WHERE u.id IN (1, 2, 3, 4)
AND NOT EXISTS
( SELECT *
FROM conversations_users AS cu
WHERE cu.user = u.id
AND cu.conversation = c.id
)
)
AND NOT EXISTS
( SELECT *
FROM conversations_users AS co -- and only them
WHERE co.conversation = c.id
AND co.user NOT IN (1, 2, 3, 4)
) ;
If you don't have a users
table or you don't like to use it (can'see why but anyway), you can replace this part:
WHERE NOT EXISTS
( SELECT *
FROM users AS u
WHERE u.id IN (1, 2, 3, 4)
AND NOT EXISTS
with:
WHERE NOT EXISTS
( SELECT *
FROM (SELECT 1 AS id UNION SELECT 2 UNION
SELECT 3 UNION SELECT 4) AS u
WHERE NOT EXISTS
The above query, while being general will not be very efficient in MySQL (blame the double nesting and the naive optimizer). The GROUP BY / COUNT
way is probably a level more efficient - but please test with your data. You can also find many more ways (more than 10) to answer this kind of question, in this answer: How to filter SQL results in a has-many-through relation Some of them do not work in MySQL but many do. I'd expect queries 5 and 6 there to be quite efficient in MySQL (a level more efficient than the group by queries).
Your case has a difference, you want exact relational division while that question/answers are about (simple) relational division, so you could write 5 like this:
SELECT id
FROM conversations AS c
WHERE EXISTS (SELECT * FROM conversations_users AS cu
WHERE cu.conversation = c.id AND cu.user = 1)
AND EXISTS (SELECT * FROM conversations_users AS cu
WHERE cu.conversation = c.id AND cu.user = 2)
AND EXISTS (SELECT * FROM conversations_users AS cu
WHERE cu.conversation = c.id AND cu.user = 3)
AND EXISTS (SELECT * FROM conversations_users AS cu
WHERE cu.conversation = c.id AND cu.user = 4)
AND NOT EXISTS (SELECT * FROM conversations_users AS cu
WHERE cu.conversation = c.id AND cu.user NOT IN (1,2,3,4))