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í: