Това е случай на релационно разделение . Събрахме арсенал от техники по този свързан въпрос:
Особената трудност е да се изключат допълнителни потребители. Основно има 4 техники.
Предлагам LEFT JOIN
/ IS NULL
:
SELECT cu1.conversation_id
FROM conversation_user cu1
JOIN conversation_user cu2 USING (conversation_id)
LEFT JOIN conversation_user cu3 ON cu3.conversation_id = cu1.conversation_id
AND cu3.user_id NOT IN (3,32)
WHERE cu1.user_id = 32
AND cu2.user_id = 3
AND cu3.conversation_id IS NULL;
Или NOT EXISTS
:
SELECT cu1.conversation_id
FROM conversation_user cu1
JOIN conversation_user cu2 USING (conversation_id)
WHERE cu1.user_id = 32
AND cu2.user_id = 3
AND NOT EXISTS (
SELECT 1
FROM conversation_user cu3
WHERE cu3.conversation_id = cu1.conversation_id
AND cu3.user_id NOT IN (3,32)
);
И двете заявки не зависи от UNIQUE
ограничение за (conversation_id, user_id)
, което може да е на място, а може и да не е. Това означава, че заявката работи дори ако user_id
32 (или 3) е посочено повече от веднъж за един и същи разговор. Вие бихте получавате обаче дублирани редове в резултата и трябва да приложите DISTINCT
или GROUP BY
.
Единственото условие е това, което формулирахте:
Проверено запитване
заявката, която сте свързали в коментара нямаше да работи. Забравихте да изключите други участници. Трябва да е нещо като:
SELECT * -- or whatever you want to return
FROM conversation_user cu1
WHERE cu1.user_id = 32
AND EXISTS (
SELECT 1
FROM conversation_user cu2
WHERE cu2.conversation_id = cu1.conversation_id
AND cu2.user_id = 3
)
AND NOT EXISTS (
SELECT 1
FROM conversation_user cu3
WHERE cu3.conversation_id = cu1.conversation_id
AND cu3.user_id NOT IN (3,32)
);
Което е подобно на другите две заявки, с изключение на това, че няма да върне няколко реда, ако user_id = 3
е свързан многократно.