MYSQL使用WHERE按ID列表搜索

时间:2017-11-04 20:06:19

标签: mysql

我有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的答案。

2 个答案:

答案 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查找l1tagid = 1)中的所有行(在索引(tagid, videoid)中搜索)
  • 使用linksl2中的tagid = 4查找videoid中的所有行(l1)(在索引(tagid, videoid)中搜索)并且在没有匹配的情况下跳过所有行。
  • 使用与linksl相同的videoid查找l1l2)中的所有行,并按videoid对其进行分组(使用索引(videoid, tagid)进行搜索和GROUP BY)

如果您需要的不仅仅是videoid,您仍然可以加入videos表格

JOIN videos v ON v.id = l.videoid

并从该表中选择您需要的内容。