Có hai cách để làm điều này. Tôi thích cách đầu tiên hơn, đó là tự tham gia cho mỗi thẻ:
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 = ?;
Cách khác cũng hoạt động, nhưng sử dụng GROUP BY
trong MySQL có xu hướng tạo ra một bảng tạm thời và hiệu suất chậm:
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;
Nhận xét lại từ @Erikoenig:
Nếu bạn muốn đảm bảo không có thẻ thừa, bạn có thể thực hiện theo cách này:
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;
Việc loại bỏ mệnh đề WHERE cho phép đếm các thẻ khác, nếu có. Vì vậy, COUNT () có thể lớn hơn 3.
Hoặc nếu số lượng chính xác là ba thẻ, nhưng một số trong ba thẻ này không phải là thẻ chính xác, thì điều kiện SUM () trong mệnh đề HAVING đảm bảo rằng tất cả ba thẻ bạn muốn đều có trong nhóm.