0

我有一个 post/tag 数据库,其中包含通常的 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})

我知道这会起作用,但是由于我的成长方式,每当我使用子查询编写查询时,我都会感到内疚(无论是否合理)。

建议更好的方法来做到这一点?

4

3 回答 3

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

于 2012-09-15T18:09:42.697 回答
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方法更容易阅读。

于 2012-09-15T18:16:38.983 回答
1
  1. 当我想获取具有 tagIdA 和 tagIdB 的帖子时,我必须使用两个连接(我最终同意了)。

    还有其他方法。

    可以通过仅对这些标签进行分组过滤,按帖子分组,然后删除包含少于预期标签的任何组,来获取所有id带有tagid123 和 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 的回答中所建议的那样。

于 2012-09-15T18:16:59.677 回答