Si votre conception applique l'intégrité référentielle, vous n'avez pas à vous joindre à la table residences
à cette fin du tout. En supposant également un UNIQUE
ou PK
contrainte sur (residence_id, amenity_id)
(sinon vous avez besoin de requêtes différentes !)
La meilleure requête dépend de ce dont vous avez besoin exactement .
En utilisant une fonction de fenêtre, vous pouvez même faire cela dans un seul niveau de requête :
SELECT count(*) OVER () AS ct
FROM listed_amenities
WHERE amenity_id IN (48, 49, 50)
GROUP BY residence_id
HAVING count(*) = 3
LIMIT 1;
Cette fonction de fenêtre ajoute le nombre total à chaque ligne sans agréger les lignes. Considérez la séquence d'événements dans un SELECT
requête :
En conséquence, vous pouvez utiliser une requête similaire pour renvoyer tous les identifiants éligibles (ou même des lignes entières) et ajouter le nombre à chaque ligne (de manière redondante) :
SELECT residence_id, count(*) OVER () AS ct
FROM listed_amenities
WHERE amenity_id IN (48, 49, 50)
GROUP BY residence_id
HAVING count(*) = 3;
Mais mieux vaut utiliser une sous-requête, c'est généralement beaucoup moins cher :
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;
Vous pourriez renvoie un tableau d'ID (par opposition à l'ensemble ci-dessus) en même temps, pour presque plus de frais :
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;
Il existe de nombreuses autres variantes, il faudrait préciser le résultat attendu. Comme celui-ci :
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;
Fondamentalement, c'est un cas de division relationnelle. Nous avons rassemblé ici un arsenal de techniques :