排除具有多对多关系的行

时间:2011-10-10 13:52:22

标签: mysql many-to-many

我有三个表:posts,tags和posts_has_tags(这有利于帖子和标签之间的多对多关系)。帖子可以包含任意数量的标签。

'posts'表格包含以下列: idposts 文本

'tags'表包含以下内容: idtags 名称

至于'posts_has_tags'表: posts_idposts tags_idtags

我不能做的是提出一个查询来选择所有帖子,除了那些在分配给它们的“名称”列中具有特定值的标签(或标签)的帖子。它似乎应该包含一个“NOT EXISTS”,但我无法完全包围它。

提前感谢您的帮助。

编辑:

另外,是否可以同时将结果集限制为某些标签?例如:

排除标签:a,b 包含的标签:c

使用标签'a'发布,'f'不会将其转换为结果集(因为如果包含标签,则不会)。 带有标签'a','b','c'的帖子也不会进入结果集(因为它的'a'和'b'是排除的标签)。 带有标签'c'的帖子,'f'会将其设为结果集,因为'c'是包含的标签。

最终编辑 我终于找到了一个似乎有效且性能相当好的解决方案:http://www.mysqldiary.com/a-many-to-many-relationship-table-solving-the-exclude-relation-problem/

4 个答案:

答案 0 :(得分:4)

您可以使用反加入。

SELECT p.* 
FROM posts p
LEFT JOIN post_has_tags pt ON (pt.post_id = p.id)
LEFT JOIN tags t ON (t.id = pt.tag_id AND t.name IN ('test','test1','test2'))
WHERE t.id IS NULL
GROUP BY p.id

如果要强制包含其他标记,则执行另一个连接。

SELECT p.* 
FROM posts p
LEFT JOIN post_has_tags pt ON (pt.post_id = p.id)
LEFT JOIN tags t ON (t.id = pt.tag_id AND t.name IN ('a','b'))
INNER JOIN tags t2 ON (t2.id <> t.id AND t2.id = pt.tag_id AND t2.name IN ('c')) 
WHERE t.id IS NULL
GROUP BY p.id

这将优先考虑排除而不是包含 如果要优先考虑包含,请将内部联接替换为:

INNER JOIN tags t2 ON (t2.id = pt.tag_id AND t2.name IN ('c')) 

答案 1 :(得分:3)

SELECT p.* 
FROM posts AS p
WHERE NOT EXISTS
      ( SELECT *
        FROM posts_has_tags AS pt
          JOIN tags AS t
            ON pt.tags_idtags = t.idtags
        WHERE pt.posts_idposts = p.idposts
          AND t.name = @CertainForbiddenTagName
      )

如果您要禁止许多标记名称,请改用:

          AND t.name IN (List of ForbiddenTagNames)

对于您更新的第二个问题,只需添加类似的EXISTS

   AND EXISTS
       ( SELECT *
         ...
       )

答案 2 :(得分:0)

select * from posts where idposts in 
(select posts_has_tags.posts_idposts from posts_has_tags   
join tags on tags.idtags = posts_has_tags.tags_idtags  
 where tags.name not in ('value1','value2',...))

答案 3 :(得分:0)

我终于找到了一个似乎有效并且表现相当出色的解决方案:http://www.mysqldiary.com/a-many-to-many-relationship-table-solving-the-exclude-relation-problem/