Este es un caso de división relacional . Hemos reunido un arsenal de técnicas bajo esta pregunta relacionada:
La dificultad especial es excluir usuarios adicionales. Hay básicamente 4 técnicas.
Sugiero 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;
O 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)
);
Ambas consultas no dependen de un UNIQUE
restricción para (conversation_id, user_id)
, que puede o no estar en su lugar. Es decir, la consulta incluso funciona si user_id
32 (o 3) aparece más de una vez para la misma conversación. Usted podría sin embargo, obtiene filas duplicadas en el resultado y necesita aplicar DISTINCT
o GROUP BY
.
La única condición es la que formulaste:
Consulta auditada
La consulta que vinculó en el comentario no funcionaría Olvidó excluir a otros participantes. Debería ser algo como:
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)
);
Lo cual es similar a las otras dos consultas, excepto que no devolverá varias filas si user_id = 3
está vinculado varias veces.