对不起,标题。我不知道如何用更清楚的方式写下来。

因此,我有theree表:


tracks,包含id(曲目ID)和name(曲目名称)
tags,包含id(标签ID)和name(标签名称)
track_tags,包含track_idtag_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;

10-04 21:52
查看更多