PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Obtenir le nombre de lignes après GROUP BY

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 :