Mysql有很多很多关系查询。如何获取过滤帖子的所有标签?

时间:2012-02-03 14:34:19

标签: mysql sql many-to-many

我在Stackoverflow中已经解决了很多关于这个问题的问题,但我认为这是不同的。

我要做的是让用户能够按标签过滤帖子,以便只看到留下过滤的标签。换句话说,如果用户选择标签“tag1”,它会显示带有该标签的帖子,并且还会显示发布共享的其他标签,但会隐藏过滤后没有可见帖子的标签。

我有表帖子 posts_tags 标签。 Posts_tags有post_id和tag_id。我设法使用特定的tagset获得post_ids:

SELECT pt.post_id
FROM posts_tags pt
    INNER JOIN tags t
        ON pt.tag_id = t.id
WHERE t.name IN ('tag1', 'tag2', 'tag3')
GROUP BY pt.post_id
HAVING COUNT(DISTINCT t.id) = 3;

假设这个查询给出了post_ids 1,2,3:

post 1 has tag1, tag2, tag3 and tag4
post 2 has tag1, tag2, tag3 and tag5
post 3 has tag1, tag2, tag3 and tag6

现在我的问题是如何扩展查询以仅将tag4,tag5和tag6 返回给用户,因为这些标记仍可用于进一步过滤帖子。怎么做到这一点?

关注表现也不错。我有130000个帖子,6500个标签和桥牌表有240000行。

编辑:使用场景:

  1. 用户使用自动填充功能查找标签并选择多个标签。
  2. 用户根据提交的标签检索帖子。
  3. 用户搜索更多标签,然后:

    我不想提供完整的清单,只提供

    一个。那还没有被选中。

    湾用于在步骤2中检索的帖子。

  4. Sample data


    编辑:基于Mosty Mostacho答案的最终查询:

    SELECT DISTINCT pt2.tag_id, t2.name FROM    
    (SELECT pt1.post_id
        FROM posts_tags pt1
        INNER JOIN tags t1
            ON pt1.tag_id = t1.id
        WHERE t1.name in ('tag1','tag2','tag3')
        GROUP BY pt1.post_id
        HAVING COUNT(DISTINCT t1.id) = 3) MatchingPosts
    INNER JOIN posts_tags pt2 ON (MatchingPosts.post_id = pt2.post_id)
    INNER JOIN tags t2 ON (pt2.tag_id = t2.id)
    WHERE t2.name NOT IN ('tag1','tag2','tag3');
    

2 个答案:

答案 0 :(得分:2)

嗯,这是我能在凌晨4:30想到的最好的事情:

SELECT distinct tag_id FROM
    (SELECT pt1.post_id FROM pt1
    INNER JOIN tags t1 ON (pt1.tag_id = t1.id)
    WHERE t1.id IN (1, 2)
    GROUP BY pt1.post_id
    HAVING COUNT(DISTINCT t1.id) = 2) MatchingPosts
INNER JOIN pt2 ON (MatchingPosts.post_id = pt2.post_id)
WHERE (pt2.tag_id NOT IN (1, 2))

(1,2)是您正在寻找的标签,当然,计数必须与您用来过滤的标签数量相匹配。

这是example(注意我稍微更改了数据)

答案 1 :(得分:0)

你的意思是扩展为只包含tag4,tag5,tag6 ......为什么不在()中更改你的WHERE t.name以反映那些标签......

或者......你的意思是它必须包括标签1,2,3,还要包括(tag4或tag5或tag6)中的任何一个......

如果是这种情况,我会改变以下的地方......

WHERE t.name IN ('tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6' )
GROUP BY pt.post_id
HAVING sum( if( t.name in ('tag1', 'tag2', 'tag3' ), 1, 0 )) = 3
  AND sum( if( t.name in  ('tag4', 'tag5', 'tag6' ), 1, 0 )) > 0