Se il tuo progetto impone l'integrità referenziale, non devi unirti alla tabella residences
assolutamente per questo scopo. Assumendo anche un UNIQUE
o PK
vincolo su (residence_id, amenity_id)
(altrimenti hai bisogno di query diverse!)
La query migliore dipende da ciò di cui hai bisogno esattamente .
Utilizzando una funzione finestra, puoi anche farlo in un unico livello di query:
SELECT count(*) OVER () AS ct
FROM listed_amenities
WHERE amenity_id IN (48, 49, 50)
GROUP BY residence_id
HAVING count(*) = 3
LIMIT 1;
Questa funzione della finestra aggiunge il conteggio totale a ogni riga senza aggregare le righe. Considera la sequenza di eventi in un SELECT
domanda:
Di conseguenza, potresti utilizzare una query simile per restituire tutti gli ID idonei (o anche intere righe) e aggiungere il conteggio a ogni riga (in modo ridondante):
SELECT residence_id, count(*) OVER () AS ct
FROM listed_amenities
WHERE amenity_id IN (48, 49, 50)
GROUP BY residence_id
HAVING count(*) = 3;
Ma è meglio usare una sottoquery, che è in genere molto più economica :
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;
Potresti restituisce una matrice di ID (al contrario di set sopra) allo stesso tempo, a quasi nessun costo aggiuntivo:
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;
Ci sono molte altre varianti, dovresti chiarire il risultato atteso. Come questo:
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;
Fondamentalmente è un caso di divisione relazionale. Abbiamo raccolto un arsenale di tecniche qui: