选择没有特定标记的帖子

时间:2012-09-15 18:06:08

标签: mysql sql many-to-many subquery

我有一个帖子/标签数据库,有通常的post,tag和tag_post表。 tag_post表包含tagid和postid字段。

我需要查询帖子。当我想要获取具有特定标记的帖子时,我必须使用连接:

... INNER JOIN tag_post ON post.id = tag_post.postid 
WHERE tag_post.tagid = {required_tagid}`

当我想要获取具有tagIdA和tagIdB的帖子时,我必须使用两个连接(我最终会达成协议)。

现在,我需要查询没有特定标签的帖子。我没有多想,只是将=更改为!=

... INNER JOIN tag_post ON post.id = tag_post.postid 
WHERE tag_post.tagid != {certain_tagid}`

轰!错误的逻辑!

我确实想到了 - 只需在这里写下逻辑:

... INNER JOIN tag_post ON post.id = tag_post.postid 
WHERE tag_post.postid NOT IN 
(SELECT postid from tag_post where tagid = {certain_tagid})

我知道这会有效,但是由于我的态度,每当我用子查询编写查询时,我都会感到内疚(无论是否合理)。

建议更好的方法吗?

3 个答案:

答案 0 :(得分:2)

您可以将其视为“在帖子中查找标签中没有匹配项的所有行(针对特定标签)”

这是LEFT JOIN的教科书用例。

LEFT JOIN tag_post ON post.id = tag_post.postid AND tag_post.tagid = {required_tagid}
WHERE tag_post.tag_id IS NULL

请注意,您必须在联接的ON子句中包含标记ID。

有关联接类型的参考,请参阅此处:http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html

答案 1 :(得分:1)

除了Gavin Towey的好答案之外,您还可以使用not exists子查询:

where   not exists
        (
        select  *
        from    tag_post
        where   post.id = tag_post.postid
                and tag_post.tagid = {required_tagid}
        )

数据库通常以相同的方式执行两种变体。我个人觉得not exists方法更容易理解。

答案 2 :(得分:1)

  1.   

    当我想要获取具有tagIdA和tagIdB的帖子时,我必须使用两个连接(我最终会达成协议)。

    还有其他方法。

    通过仅为这些标记分组过滤id,按帖子分组然后删除任何组,可以获取所有tagid 123和456标记的帖子tag_post包含的标签少于预期;然后可以使用结果来过滤posts表:

    SELECT * FROM posts WHERE id IN (
      SELECT   postid
      FROM     tag_post
      WHERE    tagid IN (123,456)
      GROUP BY postid
      HAVING   COUNT(*) = 2
    )
    

    如果帖子可以多次使用相同的tagid标记,则需要将COUNT(*)替换为性能较低的COUNT(DISTINCT tagid)

  2.   

    现在,我需要查询没有特定标记的帖子。

    这称为反连接。最简单的方法是将IN从上面的查询中替换为NOT IN,如您所建议的那样。我不会为此感到内疚。另一种方法是使用@GavinTowey's answer中建议的外连接。