2014-01-12 19 views
0

对不起,问题标题..我不知道如何以更清晰的方式写下来。Mysql:在table1中查找1行,并在给定值中连接table2中的多行

所以,我有三项方表:

  1. tracks,包含id(轨道ID)& name(曲目名称)
  2. tags,包含id(标签ID)& name(标签名)
  3. track_tags,包含track_id & tag_id

我必须找到所有标签,列表中指定的所有音轨(例如,我需要找到所有音轨,一次有'摇滚','流行'和'舞蹈'标签)。

此前,我已经解决了类似的问题,但找到至少有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服务器。

回答

2

来解决,这是使用聚合与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; 

这一细微变化是做过滤的地方,然后寻找三个不同的标签:

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; 
+0

哇。我绝对必须尝试。这是第一次,似乎拯救了我的生命。这个查询将需要大量的RAM,对吧? – avasin

+1

MySQL中的聚合查询倾向于使用外部文件排序算法。这使他们有点慢,但你必须在你的数据上尝试。 –

+0

还有一个问题:在这个查询中不应该有任何曲目重复,对吗?所有返回的'track'行逻辑上应该是唯一的,我只是为了以防万一。 – avasin

相关问题