PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Obter a contagem de linhas após GROUP BY


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: