Se seu design impõe integridade referencial, você não precisa ingressar na tabela
residences
para este fim em tudo. Também assumindo um UNIQUE
ou PK
restrição em (residence_id, amenity_id)
(senão você precisa de consultas diferentes!) A melhor consulta depende do que você precisa exatamente .
Usando uma função de janela, você pode até faça isso em um único nível de consulta:
SELECT count(*) OVER () AS ct
FROM listed_amenities
WHERE amenity_id IN (48, 49, 50)
GROUP BY residence_id
HAVING count(*) = 3
LIMIT 1;
Esta função de janela anexa a contagem total a cada linha sem agregar linhas. Considere a sequência de eventos em um
SELECT
consulta:Assim, você pode usar uma consulta semelhante para retornar todos os IDs qualificados (ou mesmo linhas inteiras) e anexar a contagem a cada linha (redundantemente):
SELECT residence_id, count(*) OVER () AS ct
FROM listed_amenities
WHERE amenity_id IN (48, 49, 50)
GROUP BY residence_id
HAVING count(*) = 3;
Mas é melhor usar uma subconsulta, que é normalmente muito mais barato :
SELECT count(*) AS ct
FROM (
SELECT 1
FROM listed_amenities
WHERE amenity_id IN (48, 49, 50)
GROUP BY residence_id
HAVING count(*) = 3
) sub;
Você poderia retornar uma matriz de IDs (em oposição ao conjunto acima) ao mesmo tempo, por quase nenhum custo adicional:
SELECT array_agg(residence_id ) AS ids, count(*) AS ct
FROM (
SELECT residence_id
FROM listed_amenities
WHERE amenity_id IN (48, 49, 50)
GROUP BY residence_id
HAVING count(*) = 3
) sub;
Existem muitas outras variantes, você teria que esclarecer o resultado esperado. Como este:
SELECT count(*) AS ct
FROM listed_amenities l1
JOIN listed_amenities l2 USING (residence_id)
JOIN listed_amenities l3 USING (residence_id)
WHERE l1.amenity_id = 48
AND l2.amenity_id = 49
AND l2.amenity_id = 50;
Basicamente é um caso de divisão relacional. Reunimos aqui um arsenal de técnicas: