我有3个表:'视频','标签'和'链接'。以下是链接表的示例:
mysql> select * from links;
+----+-------+---------+
| id | tagid | videoid |
+----+-------+---------+
| 25 | 6 | 35 |
| 24 | 5 | 7 |
| 23 | 1 | 7 |
| 22 | 7 | 3 |
| 21 | 1 | 3 |
+----+-------+---------+
5 rows in set (0.00 sec)
要获取每个视频的标签列表,我使用此查询:
SELECT v.id, GROUP_CONCAT(l.tagid) as tags FROM videos v LEFT JOIN links l ON l.videoid = v.id GROUP BY v.id;
+----+------+
| id | tags |
+----+------+
| 30 | NULL |
| 31 | 2 |
| 32 | 1,3 |
| 33 | 1 |
| 34 | 1,2 |
+----+------+
5 rows in set (0.02 sec)
但是如何搜索包含标签列表的视频?目前我在查询结尾添加HAVING
子句。
例如,我有三个标签为'1','1,4','1,4,7'的视频。为了找到包含标签1和4的视频,我添加了HAVING sum(tagid = 1) > 0 AND sum(tagid = 4) > 0
。它返回最后两个视频。这是类似问题的解决方案。使用WHERE
子句对我来说会更方便,因此我正在寻找WHERE
的答案。
答案 0 :(得分:1)
你可以用in子句过滤你需要的标签,并且有计数(disctinct tagid)等于你需要的标签数量,例如两个标签名为tagid1,tagid2
SELECT v.id, GROUP_CONCAT(l.tagid) as tags
FROM videos v
where l.tagid in( tagid1, tagid2)
LEFT JOIN links l ON l.videoid = v.id GROUP BY v.id
having count(dictinct tagid) = 2;
否则,如果您还需要包含2个标签但也包含其他标签的视频,则应删除having子句
SELECT v.id, GROUP_CONCAT(l.tagid) as tags
FROM videos v
where l.tagid in( tagid1, tagid2)
LEFT JOIN links l ON l.videoid = v.id GROUP BY v.id
或者你可以使用in子句与视频匹配标签
SELECT v.id, GROUP_CONCAT(l.tagid) as tags
FROM videos v
where v.id in (
select videos.id
from videos
INNER JOIN links on links.videoid = video.id
and links.tagid in ( tagid1, tagid2)
)
GROUP BY v.id
答案 1 :(得分:1)
据我了解,您的实际工作查询是
SELECT v.id, GROUP_CONCAT(l.tagid) as tags
FROM videos v
LEFT JOIN links l ON l.videoid = v.id
GROUP BY v.id
HAVING sum(tagid = 1) > 0
AND sum(tagid = 4) > 0
只要桌子不是太大,这个(恕我直言)就可以了。但是,在此HAVING条件下,您的JOIN在逻辑上变为INNER JOIN。如果您只需要id
个视频,则可以选择l.videoid
而无需触及videos
表格。
SELECT l.videoid, GROUP_CONCAT(l.tagid) as tags
FROM links l
GROUP BY l.videoid
HAVING sum(tagid = 1) > 0
AND sum(tagid = 4) > 0
但这需要在links
表上进行全表扫描,这可能是大数据集上的性能问题。为了获得更好的性能,您可以尝试以下查询:
SELECT l.videoid, GROUP_CONCAT(l.tagid) as tags
FROM links l
JOIN links l1 USING(videoid)
JOIN links l2 USING(videoid)
WHERE l1.tagid = 1
AND l2.tagid = 4
鉴于links(tagid, videoid)
和links(videoid, tagid)
上的索引,执行计划应为:
links
查找l1
(tagid = 1
)中的所有行(在索引(tagid, videoid)
中搜索)links
和l2
中的tagid = 4
查找videoid
中的所有行(l1
)(在索引(tagid, videoid)
中搜索)并且在没有匹配的情况下跳过所有行。links
和l
相同的videoid
查找l1
(l2
)中的所有行,并按videoid
对其进行分组(使用索引(videoid, tagid)
进行搜索和GROUP BY)如果您需要的不仅仅是videoid
,您仍然可以加入videos
表格
JOIN videos v ON v.id = l.videoid
并从该表中选择您需要的内容。