Dazu gibt es zwei Möglichkeiten. Ich bevorzuge den ersten Weg, der darin besteht, sich für jedes Tag selbst beizutreten:
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 = ?;
Der andere Weg funktioniert auch, aber mit GROUP BY
in MySQL neigt dazu, eine temporäre Tabelle zu erzeugen, und die Leistung ist langsam:
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-Kommentar von @Erikoenig:
Wenn Sie sicherstellen möchten, dass keine zusätzlichen Tags vorhanden sind, können Sie dies folgendermaßen tun:
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;
Das Weglassen der WHERE-Klausel erlaubt es, andere Tags zu zählen, falls es welche gibt. Daher kann COUNT() größer als 3 sein.
Oder wenn genau drei Tags gezählt werden, aber einige dieser drei nicht die richtigen Tags sind, dann stellt die SUM()-Bedingung in der HAVING-Klausel sicher, dass alle drei gewünschten Tags in der Gruppe vorhanden sind.