对不起,标题。我不知道如何用更清楚的方式写下来。
因此,我有theree表:tracks
,包含id
(曲目ID)和name
(曲目名称)tags
,包含id
(标签ID)和name
(标签名称)track_tags
,包含track_id
和tag_id
我必须查找列表中指定的所有具有所有标签的轨道(例如,我需要一次查找具有“ rock”,“ pop”和“ dance”标签的所有轨道)。
以前,我已经解决了类似的问题,但是找到了至少匹配1个标签的所有曲目。这很简单:
SELECT tracks.*
FROM tags
INNER JOIN track_tags ON tags.id = track_tags.tag_id
INNER JOIN tracks ON track_tags.track_id = tracks.id
WHERE tags.name IN('pop', 'rock', 'dance')
GROUP BY tracks.id
但是我完全不知道如何找到所有曲目,这些曲目与列表中的所有标签完全匹配。
我曾考虑过将所有曲目及其所有标签检索到我的应用程序中,并在其中过滤曲目-但其中有很多(数十万个),应用程序也使用了分页功能,可以在上方查询中使用LIMIT轻松实现。
也许可以使用MySQL功能以另一种方式完成?我真的很沮丧,选择带有所有标签的所有曲目并在应用程序端对其进行过滤将杀死Web服务器。
最佳答案
解决此问题的最通用方法是使用带有having
子句的聚合:
SELECT tracks.*
FROM tags INNER JOIN
track_tags
ON tags.id = track_tags.tag_id INNER JOIN
tracks
ON track_tags.track_id = tracks.id
GROUP BY tracks.id
HAVING sum(tags.name = 'pop') > 0 and
sum(tags.name = 'rock') > 0 and
sum(tags.name = 'dance') > 0;
这方面的一个细微变化是在where中进行过滤,然后寻找三个不同的标签:
SELECT tracks.*
FROM tags INNER JOIN
track_tags
ON tags.id = track_tags.tag_id INNER JOIN
tracks
ON track_tags.track_id = tracks.id
WHERE tags.name IN('pop', 'rock', 'dance')
GROUP BY tracks.id
HAVING count(distinct tags.name) = 3;