4

在这里潜伏了很长时间,多年来一直在使用这个网站的建议,现在我有一个我找不到答案的问题 - 我相信解决方案很简单!

我正在为音乐曲目建立一个标记系统。我有三张桌子

曲目

---------------
| id | name   |
---------------
| 1  | Track1 |
| 2  | Track2 |
---------------

标签链接

--------------------------
| id | tag_id | track_id |
--------------------------
| 1  | 1      | 1        | 
| 2  | 2      | 1        | 
| 3  | 2      | 2        |
--------------------------

标签

-------------------------
| id | tag      | type  |
-------------------------
| 1  | acoustic | genre | 
| 2  | anger    | mood  |
-------------------------

我希望能够获取具有例如标签:声学,类型:流派和标签:愤怒,类型:情绪的曲目的曲目名称。所以在这种情况下,我想要轨道 1,因为它有两个标签。

我目前的查询是

SELECT tracks.name 
FROM tracks
JOIN taglinks ON tracks.id=taglinks.track_id
JOIN tags ON (tags.type='genre' AND tags.tag='acoustic') AND (tags.type='mood' AND tags.tag='anger')
WHERE taglinks.tag_id=tags.id;

这不会返回任何内容,如果我删除第二个 JOIN 中的 AND 部分,那么我会按预期将所有轨道标记为声学,如果我将其更改为 OR,我会再次按预期获得两个轨道。

我如何执行 AND 并仅返回同时具有这些标签和类型的曲目?

先谢谢了

编辑:

只是为了澄清我所追求的。我希望能够检索同时具有 Acoustic 和 Anger 作为标签的曲目,但前提是这些标签也与给定类型匹配。

这是因为稍后我可能有一个名为 jazz 的类型为类型的标签,以及一个名为 jazz 的类型为风格的标签,我需要能够确保我选择了正确的标签类型以及标签本身。

这是我正在使用的 sqlfiddle 的链接 - http://sqlfiddle.com/#!2/aad82/3

到目前为止,吉尔斯的回答似乎是一个很好的解决方案!

4

3 回答 3

2

这应该没问题

select
t.name
from
tracks as t 
inner join taglinks as tl on t.id = tl.track_id
inner join tags as tg on tl.tag_id = tg.id
where
tg.tag = 'acoustic' and
tg.type = 'genre' and 
tg.tag = 'anger' and
tg.type = 'mood';

注意:我as identifier喜欢这样使用,因为它可以节省在任何地方写入表名。你不必。

编辑

我可能有点误解了你的问题,所以这个问题也可能有所帮助:

select
t.name
from
tracks as t 
inner join taglinks as tl on t.id = tl.track_id
inner join tags as tg on tl.tag_id = tg.id
where
(tg.tag = 'acoustic' and
tg.type = 'genre') or 
(tg.tag = 'anger' and
tg.type = 'mood');

这将带回具有正确类型和标签但不必拥有所有标签的结果。

于 2012-12-13T15:26:26.857 回答
1
SELECT * FROM tracks tracks
INNER JOIN
(SELECT taglinks.track_id, COUNT(*) as cnt
FROM tags tags
INNER JOIN taglinks taglinks ON taglinks.tag_id = tags.id
WHERE
    (tags.tag='ac' AND tags.type='ge')
    OR (tags.tag='an' AND tags.type='mo')
GROUP BY taglinks.track_id
)AS track_match
    ON track_match.track_id = tracks.id AND track_match.cnt = 2

您将需要替换 "track_match.cnt = 2" 2=要匹配的条件数

此解决方案提供了一些灵活性:您还可以让轨道满足最少数量的条件。

例如,您可以在此处添加 track_match.cnt >= 1 以及 ORDER BY track_match.cnt DESC

获取按匹配条件数排序的曲目列表。

于 2012-12-13T17:29:33.997 回答
1

问题是轨道应该有 2 个标签等于要求的值,所有发布的请求在这种情况下都不起作用。必须使用 INTERSECT sql 命令,但这个命令在 mysql 中不可用。

类似的东西应该可以工作:

SELECT tracks.id, tracks.name
FROM  `taglinks` 
LEFT JOIN tags ON tags.id = taglinks.tag_id
LEFT JOIN tracks ON tracks.id = taglinks.track_id
WHERE (
tag =  'accoustic'
AND `type` =  'genre'
)
OR (
tag =  'anger'
AND `type`=  'mood'
)
GROUP BY track_id
HAVING COUNT( * ) =2
  • 我选择与至少一个标签匹配的所有行
  • 我计算与 a 匹配的标签数量GROUP BY
  • 如果我搜索两个参数(here accoustic = 'genre'and anger = 'mood'found 2 rows for this track then it matches the 2 conditions and I keep it to the final result
  • 只要记住HAVING COUNT( * ) =2用我们要搜索的标签数来改变
于 2012-12-13T16:37:16.080 回答