mysql - 选择所有未标记为隐藏的帖子

时间:2013-05-05 17:39:44

标签: mysql sql relational-database

所以我有三个表,一个是posts,有id,title,content,timestamp列。其他为tags,列id,tag,第三posttags描述poststags之间的一对多关系,列postid,tagid

现在,不要在表hidden,featured中使用posts等列来描述帖子应该对所有人可见还是应该显示在特殊的精选页面上,我想为什么不用标签来节省时间。所以我决定所有标记为#featured的帖子都会被展示,所有标记为#hidden的帖子都会被隐藏。

实现第一个很简单,因为我可以使用连接查询,在我的where子句中我可以提到WHERE tag='featured',这将获得我的所有精选帖子。

但如果我要使用查询,请举例说明标记为#sports#hidden的帖子

SELECT * FROM posts
INNER JOIN posttags ON posttags.postid = posts.id
INNER JOIN tags ON posttags.tagid = tags.id
WHERE tag !='hidden'

但是仍然会返回标记为hidden的帖子,因为它还标记了sports

PS 我的问题与此问题不同:Select a post that does not have a particular tag因为它直接使用tagid而我无法使用double join来检查标记名称而不是tagid。而且我希望在相同的查询中检索帖子的其他标签,这在该问题的答案中使用该方法是不可能的

2 个答案:

答案 0 :(得分:4)

通过发布对标记进行分组,然后使用HAVING子句过滤那些不包含'hidden'标记的组。由于MySQL的隐式类型转换和缺乏真正的布尔类型,可以做到:

SELECT   posts.*
FROM     posts
    JOIN posttags ON posttags.postid = posts.id
    JOIN tags     ON posttags.tagid  = tags.id
GROUP BY posts.id
HAVING   NOT SUM(tag='hidden')

答案 1 :(得分:1)

您可以使用NOT EXISTS子查询执行此操作:

SELECT p.*, t.*                          -- what columns you need
FROM posts AS p
  INNER JOIN posttags AS pt
    ON pt.postid = p.id
  INNER JOIN tags AS t
    ON pt.tagid = t.id
WHERE NOT EXISTS
      ( SELECT *
        FROM posttags AS pt_no
          INNER JOIN tags AS t_no
            ON pt_no.tagid = t_no.id
        WHERE t_no.tag = 'hidden'
          AND pt_no.postid = p.id
      ) ;

或等效的LEFT JOIN / IS NULL

SELECT p.*, t.* 
FROM posts AS p
  LEFT JOIN posttags AS pt_no
      INNER JOIN tags AS t_no
        ON  t_no.tag = 'hidden'
        AND pt_no.tagid = t_no.id
    ON pt_no.postid = p.id
  INNER JOIN posttags AS pt
    ON pt.postid = p.id
  INNER JOIN tags AS t
    ON pt.tagid = t.id
WHERE pt_no.postid IS NULL ;

Thsi类型的查询称为反半连接或仅反连接。在你的情况下,它稍微复杂一些,因为条件(tag='hidden')在第3个表中。