有两种方法可以做到这一点。我更喜欢第一种方式,即为每个标签自加入:
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 = ?;
另一种方式也可以,但是GROUP BY
在 MySQL 中使用往往会产生临时表并且性能很慢:
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;
来自@Erikoenig 的重新评论:
如果你想确保没有额外的标签,你可以这样做:
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;
取出 WHERE 子句允许计算其他标签(如果有的话)。所以 COUNT() 可能大于 3。
或者如果计数正好是三个标签,但是这三个标签中的一些不是正确的标签,那么 HAVING 子句中的 SUM() 条件确保您想要的所有三个标签都存在于组中。