Als uw ontwerp referentiële integriteit afdwingt, hoeft u zich niet aan te sluiten bij de tabel residences
helemaal voor dit doel. Ook uitgaande van een UNIQUE
of PK
beperking op (residence_id, amenity_id)
(anders heb je andere vragen nodig!)
De beste zoekopdracht hangt af van wat u precies nodig heeft .
Met behulp van een vensterfunctie kunt u kunt doe dit zelfs op een enkel zoekniveau:
SELECT count(*) OVER () AS ct
FROM listed_amenities
WHERE amenity_id IN (48, 49, 50)
GROUP BY residence_id
HAVING count(*) = 3
LIMIT 1;
Deze vensterfunctie voegt de totale telling toe aan elke rij zonder rijen samen te voegen. Overweeg de volgorde van gebeurtenissen in een SELECT
vraag:
Dienovereenkomstig kunt u een vergelijkbare zoekopdracht gebruiken om alle in aanmerking komende ID's (of zelfs hele rijen) te retourneren en de telling (redundant) aan elke rij toe te voegen:
SELECT residence_id, count(*) OVER () AS ct
FROM listed_amenities
WHERE amenity_id IN (48, 49, 50)
GROUP BY residence_id
HAVING count(*) = 3;
Maar gebruik liever een subquery, dat is meestal veel goedkoper :
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;
Je zou een array van ID's retourneren (in tegenstelling tot de set hierboven) tegelijkertijd, voor nauwelijks meer 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;
Er zijn veel andere varianten, u zou het verwachte resultaat moeten verduidelijken. Zoals deze:
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;
Eigenlijk is het een kwestie van relationele verdeling. We hebben hier een arsenaal aan technieken verzameld: