Om din design upprätthåller referensintegritet behöver du inte gå med i tabellen residences
överhuvudtaget för detta ändamål. Förutsätter också en UNIQUE
eller PK
begränsning på (residence_id, amenity_id)
(annars behöver du andra frågor!)
Den bästa frågan beror på vad du behöver exakt .
Genom att använda en fönsterfunktion kan gör även detta på en enda frågenivå:
SELECT count(*) OVER () AS ct
FROM listed_amenities
WHERE amenity_id IN (48, 49, 50)
GROUP BY residence_id
HAVING count(*) = 3
LIMIT 1;
Denna fönsterfunktion lägger till det totala antalet till varje rad utan att aggregera rader. Tänk på händelseförloppet i en SELECT
fråga:
Följaktligen kan du använda en liknande fråga för att returnera alla kvalificerande ID:n (eller till och med hela rader) och lägga till antalet till varje rad (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 det är bättre att använda en underfråga, det är vanligtvis mycket billigare :
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 kunde returnera en rad ID:n (till skillnad från uppsättningen). ovan) samtidigt, för knappast någon mer kostnad:
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;
Det finns många andra varianter, du måste förtydliga det förväntade resultatet. Som den här:
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;
I grund och botten är det ett fall av relationell uppdelning. Vi har samlat en arsenal av tekniker här: