Ada dua cara untuk melakukan ini. Saya lebih suka cara pertama, yaitu self-join untuk setiap 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 = ?;
Cara lain juga berfungsi, tetapi menggunakan GROUP BY
di MySQL cenderung menimbulkan tabel sementara dan kinerjanya lambat:
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;
Komentar ulang dari @Erikoenig:
Jika Anda ingin memastikan tidak ada tag tambahan, Anda dapat melakukannya dengan cara ini:
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;
Menghapus klausa WHERE memungkinkan tag lain dihitung, jika ada. Jadi COUNT() mungkin lebih besar dari 3.
Atau jika hitungannya tepat tiga tag, tetapi beberapa dari ketiga tag tersebut bukan tag yang benar, maka kondisi SUM() pada klausa HAVING memastikan bahwa ketiga tag yang Anda inginkan ada dalam grup.