To jest przypadek podziału relacyjnego . W ramach tego pytania zebraliśmy cały arsenał technik:
Szczególną trudnością jest wykluczenie dodatkowych użytkowników. Istnieją zasadniczo 4 techniki.
Proponuję 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;
Lub 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)
);
Oba zapytania nie zależą od UNIQUE
ograniczenie dla (conversation_id, user_id)
, który może, ale nie musi, być na miejscu. Oznacza to, że zapytanie działa nawet wtedy, gdy user_id
32 (lub 3) jest wymieniony więcej niż raz dla tej samej rozmowy. chciałbyś uzyskaj jednak zduplikowane wiersze w wyniku i musisz zastosować DISTINCT
lub GROUP BY
.
Jedyny warunek to ten, który sformułowałeś:
Skontrolowane zapytanie
zapytanie połączone w komentarzu nie zadziała. Zapomniałeś wykluczyć innych uczestników. Powinno być coś takiego:
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)
);
Co jest podobne do pozostałych dwóch zapytań, z tą różnicą, że nie zwróci wielu wierszy, jeśli user_id = 3
jest połączony wiele razy.