1

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

现在,与其在表格中使用诸如hidden,featuredetc 之类的列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我的问题与这个问题不同:选择一个没有特定标签的帖子,因为它直接使用tagid,我无法使用双连接来检查标签名称而不是tagid来获得相同的结果。而且我希望在同一查询中检索帖子的其他标签,这是使用该问题答案中的方法无法实现的

4

2 回答 2

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')
于 2013-05-05T17:47:47.033 回答
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 ;

这种类型的查询称为反半连接或只是反连接。在您的情况下,它稍微复杂一些,因为条件 ( tag='hidden') 在第三个表中。

于 2013-05-05T18:02:13.573 回答