PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Encontrar linhas que tenham o mesmo valor em uma coluna e outros valores em outra coluna?


Este é um caso de divisão relacional . Reunimos um arsenal de técnicas sob esta questão relacionada:

A dificuldade especial é excluir usuários adicionais. Existem basicamente 4 técnicas.

Sugiro 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;

Ou 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 as consultas não dependem de um UNIQUE restrição para (conversation_id, user_id) , que pode ou não estar em vigor. Ou seja, a consulta funciona mesmo se user_id 32 (ou 3) é listado mais de uma vez para a mesma conversa. Você faria obter linhas duplicadas no resultado, porém, e precisa aplicar DISTINCT ou GROUP BY .
A única condição é a que você formulou:

Consulta auditada


A consulta que você vinculou no comentário não funcionaria. Você esqueceu de excluir outros participantes. Deve 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)
   );

Que é semelhante às outras duas consultas, exceto que não retornará várias linhas se user_id = 3 está vinculado várias vezes.