Questo è un caso di divisione relazionale . Abbiamo assemblato un arsenale di tecniche sotto questa domanda correlata:
La difficoltà particolare consiste nell'escludere utenti aggiuntivi. Ci sono fondamentalmente 4 tecniche.
Suggerisco 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;
Oppure 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)
);
Entrambe le query non dipendono da un UNIQUE
vincolo per (conversation_id, user_id)
, che può essere o meno presente. Ciò significa che la query funziona anche se user_id
32 (o 3) è elencato più di una volta per la stessa conversazione. lo faresti ottieni righe duplicate nel risultato, tuttavia, e devi applicare DISTINCT
o GROUP BY
.
L'unica condizione è quella che hai formulato:
Query controllata
La query che hai collegato nel commento non funzionerebbe. Hai dimenticato di escludere altri partecipanti. Dovrebbe essere qualcosa del tipo:
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)
);
Che è simile alle altre due query, tranne per il fatto che non restituirà più righe se user_id = 3
è collegato più volte.