Dies ist ein Fall von relationaler Teilung . Unter dieser verwandten Frage haben wir ein Arsenal an Techniken zusammengestellt:
Die besondere Schwierigkeit besteht darin, weitere Nutzer auszuschließen. Grundsätzlich gibt es 4 Techniken.
Ich schlage LEFT JOIN
vor / 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;
Oder 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)
);
Beide Abfragen nicht hängen von einem UNIQUE
ab Einschränkung für (conversation_id, user_id)
, die vorhanden sein können oder nicht. Das heißt, die Abfrage funktioniert sogar, wenn user_id
32 (oder 3) wird mehr als einmal für dieselbe Konversation aufgeführt. Sie würden erhalten jedoch doppelte Zeilen im Ergebnis und müssen DISTINCT
anwenden oder GROUP BY
.
Die einzige Bedingung ist die, die Sie formuliert haben:
Geprüfte Abfrage
Die Abfrage, die Sie im Kommentar verlinkt haben würde nicht funktionieren. Sie haben vergessen, andere Teilnehmer auszuschließen. Sollte etwa so aussehen:
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)
);
Dies ähnelt den anderen beiden Abfragen, außer dass es nicht mehrere Zeilen zurückgibt, wenn user_id = 3
ist mehrfach verlinkt.