Ci sono due modi per farlo. Preferisco il primo modo, che consiste nell'unirsi automaticamente per ogni tag:
SELECT l.*
FROM Locations l
JOIN LocationsTagsAssoc a1 ON a1.LocationID = l.ID
JOIN Tags t1 ON a1.TagID = t1.ID AND t1.Name = ?
JOIN LocationsTagsAssoc a2 ON a2.LocationID = l.ID
JOIN Tags t2 ON a2.TagID = t2.ID AND t2.Name = ?
JOIN LocationsTagsAssoc a3 ON a3.LocationID = l.ID
JOIN Tags t3 ON a3.TagID = t3.ID AND t3.Name = ?;
Funziona anche l'altro modo, ma usando GROUP BY
in MySQL tende a incorrere in una tabella temporanea e le prestazioni sono lente:
SELECT l.*
FROM Locations l
JOIN LocationsTagsAssoc a ON a.LocationID = l.ID
JOIN Tags t ON a.TagID = t.ID
WHERE t.Name IN (?, ?, ?)
GROUP BY l.ID
HAVING COUNT(*) = 3;
Re commento da @Erikoenig:
Se vuoi assicurarti che non ci siano tag extra, puoi farlo in questo modo:
SELECT l.*
FROM Locations l
JOIN LocationsTagsAssoc a ON a.LocationID = l.ID
JOIN Tags t ON a.TagID = t.ID
GROUP BY l.ID
HAVING COUNT(*) = 3 AND SUM(t.Name IN (?, ?, ?)) = 3;
Eliminare la clausola WHERE consente di contare altri tag, se presenti. Quindi COUNT() potrebbe essere maggiore di 3.
Oppure, se il conteggio è esattamente di tre tag, ma alcuni di questi tre non sono i tag corretti, la condizione SUM() nella clausola HAVING assicura che tutti e tre i tag desiderati siano presenti nel gruppo.