Eu tenho duas tabelas com uma chave estrangeira de T1->T2, em um relacionamento um-para-muitos. Ou seja, 1 tupla na tabela T1 está associada a 0..N tuplas em T2.
Para criar um exemplo simples, digamos que T1 é Carros e T2 é uma tabela de imperfeições. Então, um carro pode ter 0..N imperfeições, e armazenamos essas imperfeições em T2 como números inteiros.
Eu gostaria de selecionar * apenas daqueles carros em Carros que contêm imperfeições i1 E i2.
Em vez disso, executar uma OU é muito fácil:
SELECT * FROM cars AS T1
WHERE EXISTS (
SELECT imperfection FROM Imperfections as T2
WHERE T1.uid = T2.uid AND (imperfection = 1 OR imperfection = 2)
);
Tenho tentado definir a lógica usando a interseção, mas, neste ponto, estou me perguntando se estou complicando demais.
Você poderia ter duas cláusulas existentes separadas:
Isso significa duas semijunções à esquerda em sua tabela de imperfeições, mas se você tiver um Ãndice em UID e imperfeição, essas devem ser triviais.
Há duas vantagens em usar WHERE EXISTS sobre JOIN neste caso. A primeira é que um semi-join esquerdo para após a primeira correspondência, portanto, pode ser mais rápido que um join (que precisa passar por todos os registros). A segunda é que, se de alguma forma você não tiver boas restrições de dados e tiver dois registros em Imperfeições com o mesmo UID e Imperfeição, poderá acabar com linhas duplicadas em sua consulta principal.
O caminho mais curto e mais
fácilde percorrer éO
(INNER) JOINs
teste para a própria existência.Isso vale se
(uid, imperfection)
forUNIQUE
, o que seria plausÃvel aqui, mas não foi definido. Pode haver subtipos de imperfeições ... então você precisa de umDISTINCT
ouGROUP BY
.USING (uid)
seria ainda mais curto do queON c.uid = i1.uid
. As imperfeições entrariam em umaWHERE
cláusula então.A próxima ideia seria a mesma que Kevin descreve em sua resposta, então não a incluirei aqui.