Pokud váš návrh vynucuje referenční integritu, nemusíte se připojovat k tabulce residences
pro tento účel vůbec. Také za předpokladu UNIQUE
nebo PK
omezení na (residence_id, amenity_id)
(jinak potřebujete jiné dotazy!)
Nejlepší dotaz závisí na tom, co přesně potřebujete .
Pomocí funkce okna můžete dokonce to udělat na úrovni jediného dotazu:
SELECT count(*) OVER () AS ct
FROM listed_amenities
WHERE amenity_id IN (48, 49, 50)
GROUP BY residence_id
HAVING count(*) = 3
LIMIT 1;
Tato funkce okna připojí celkový počet ke každému řádku bez agregace řádků. Zvažte sled událostí v SELECT
dotaz:
V souladu s tím můžete použít podobný dotaz k vrácení všech způsobilých ID (nebo dokonce celých řádků) a připojit počet ke každému řádku (redundantně):
SELECT residence_id, count(*) OVER () AS ct
FROM listed_amenities
WHERE amenity_id IN (48, 49, 50)
GROUP BY residence_id
HAVING count(*) = 3;
Ale raději použijte poddotaz, ten je obvykle mnohem levnější :
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;
Mohli byste vrátí pole ID (na rozdíl od set výše) ve stejnou dobu za téměř žádné další náklady:
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;
Existuje mnoho dalších variant, museli byste si ujasnit očekávaný výsledek. Jako tento:
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;
V podstatě je to případ relačního rozdělení. Zde jsme shromáždili arzenál technik: