Wenn Ihr Design referentielle Integrität erzwingt, müssen Sie der Tabelle residences
nicht beitreten überhaupt zu diesem Zweck. Auch unter der Annahme eines UNIQUE
oder PK
Beschränkung auf (residence_id, amenity_id)
(Andernfalls benötigen Sie andere Abfragen!)
Die beste Abfrage hängt davon ab, was Sie genau benötigen .
Mit einer Fensterfunktion können Sie das können tun Sie dies sogar auf einer einzigen Abfrageebene:
SELECT count(*) OVER () AS ct
FROM listed_amenities
WHERE amenity_id IN (48, 49, 50)
GROUP BY residence_id
HAVING count(*) = 3
LIMIT 1;
Diese Fensterfunktion hängt die Gesamtzahl an jede Zeile an, ohne Zeilen zu aggregieren. Betrachten Sie die Abfolge von Ereignissen in einem SELECT
Abfrage:
Dementsprechend könnten Sie eine ähnliche Abfrage verwenden, um alle qualifizierenden IDs (oder sogar ganze Zeilen) zurückzugeben und die Anzahl an jede Zeile (redundant) anzuhängen:
SELECT residence_id, count(*) OVER () AS ct
FROM listed_amenities
WHERE amenity_id IN (48, 49, 50)
GROUP BY residence_id
HAVING count(*) = 3;
Aber verwenden Sie besser eine Unterabfrage, das ist in der Regel viel billiger :
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;
Sie könnten gibt ein Array von IDs zurück (im Gegensatz zum set oben) gleichzeitig für kaum mehr Kosten:
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;
Es gibt noch viele andere Varianten, man müsste das erwartete Ergebnis abklären. Wie dieses hier:
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;
Im Grunde ist es ein Fall von relationaler Teilung. Wir haben hier ein Arsenal an Techniken zusammengestellt: