Er zijn twee manieren om dit te doen. Ik geef de voorkeur aan de eerste manier, namelijk om voor elke tag zelf lid te worden:
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 = ?;
De andere manier werkt ook, maar met GROUP BY
in MySQL heeft de neiging om een tijdelijke tabel op te lopen en de prestaties zijn traag:
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 reactie van @Erikoenig:
Als u er zeker van wilt zijn dat er geen extra tags zijn, kunt u dit op deze manier doen:
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;
Door de WHERE-component te verwijderen, kunnen andere tags worden geteld, als die er zijn. Dus COUNT() kan groter zijn dan 3.
Of als het aantal precies drie tags is, maar sommige van deze drie zijn niet de juiste tags, dan zorgt de SUM()-voorwaarde in de HAVING-component ervoor dat alle drie de tags die u wilt aanwezig zijn in de groep.