sql >> Base de Datos >  >> RDS >> PostgreSQL

Obtenga el recuento de filas después de GROUP BY

Si su diseño exige integridad referencial, no tiene que unirse a la tabla residences para este propósito en absoluto. También asumiendo un UNIQUE o PK restricción en (residence_id, amenity_id) (¡de lo contrario, necesita consultas diferentes!)

La mejor consulta depende de lo que necesite exactamente .

Con una función de ventana, puede incluso haz esto en un solo nivel 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 función de ventana agrega el recuento total a cada fila sin agregar filas. Considere la secuencia de eventos en un SELECT consulta:

En consecuencia, podría utilizar una consulta similar para devolver todos los ID válidos (o incluso filas completas) y agregar el recuento a cada fila (redundante):

SELECT residence_id, count(*) OVER () AS ct
FROM   listed_amenities
WHERE  amenity_id IN (48, 49, 50)
GROUP  BY residence_id
HAVING count(*) = 3;

Pero es mejor usar una subconsulta, eso es generalmente mucho más 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;

podrías devolver una matriz de ID (a diferencia del conjunto arriba) al mismo tiempo, por apenas más costo:

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;

Hay muchas otras variantes, habría que aclarar el resultado esperado. Me gusta 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;

Básicamente es un caso de división relacional. Hemos reunido un arsenal de técnicas aquí: