PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Zeilen finden, die denselben Wert in einer Spalte und andere Werte in einer anderen Spalte haben?

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.