Hvis dit design håndhæver referentiel integritet, behøver du ikke at slutte dig til tabellen residences
overhovedet til dette formål. Antager også en UNIQUE
eller PK
begrænsning på (residence_id, amenity_id)
(ellers har du brug for forskellige forespørgsler!)
Den bedste forespørgsel afhænger af, hvad du har brug for præcis .
Ved at bruge en vinduesfunktion kan selv gør dette på et enkelt forespørgselsniveau:
SELECT count(*) OVER () AS ct
FROM listed_amenities
WHERE amenity_id IN (48, 49, 50)
GROUP BY residence_id
HAVING count(*) = 3
LIMIT 1;
Denne vinduesfunktion tilføjer det samlede antal til hver række uden at aggregere rækker. Overvej rækkefølgen af hændelser i en SELECT
forespørgsel:
Derfor kan du bruge en lignende forespørgsel til at returnere alle kvalificerende id'er (eller endda hele rækker) og tilføje optællingen til hver række (redundant):
SELECT residence_id, count(*) OVER () AS ct
FROM listed_amenities
WHERE amenity_id IN (48, 49, 50)
GROUP BY residence_id
HAVING count(*) = 3;
Men brug hellere en underforespørgsel, det er typisk meget billigere :
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;
Du kunne returnere en række id'er (i modsætning til sættet ovenfor) på samme tid, for næppe flere omkostninger:
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;
Der er mange andre varianter, du bliver nødt til at afklare det forventede resultat. Som denne:
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;
Grundlæggende er det et tilfælde af relationel opdeling. Vi har samlet et arsenal af teknikker her: