2009-12-09 74 views
2

我有“文章”之间的关系HABTM“标签”HABTM查询帮助

问题:我只寻找与这两个标签“体育”的文章和“户外”,但不是唯一的文章其中一个标签。

我尝试这样做:

SELECT DISTINCT article.id, article.name FROM articles 
inner JOIN tags ON (tags.name IN ('outdoors', 'sports') 
inner JOIN articles_tags ON articles_tags.article_id = article.id AND articles_tags.tag_id = tags.id 

...但它让我的文章是在只有运动,只有户外运动都在户外+

问题什么是使用权查询? (我使用MySQL)

回答

0

有两个共同的解决办法。

  • 第一个解决方案使用GROUP BY来算匹配“户外”是每篇文章的标签或“运动”,然后只返回有两个标签中的组。

    SELECT a.id, a.name 
    FROM articles AS a 
    INNER JOIN articles_tags AS at ON (a.id = at.article_id) 
    INNER JOIN tags AS t ON (t.id = at.tag_id) 
    WHERE t.name IN ('outdoors', 'sports') 
    GROUP BY a.id 
    HAVING COUNT(DISTINCT t.name) = 2; 
    

    这种解决办法似乎更易读的一些人,并添加值是更简单的。但是在MySQL中的GROUP BY查询往往会产生一个危害性能的临时表。

  • 另一种解决方案使用每个不同标记的JOIN。通过使用内部连接,查询自然会限制为匹配您指定的所有标签的文章。

    SELECT a.id, a.name 
    FROM articles AS a 
    INNER JOIN articles_tags AS at1 ON (a.id = at1.article_id) 
    INNER JOIN tags AS t1 ON (t1.id = at1.tag_id AND t1.name = 'outdoors') 
    INNER JOIN articles_tags AS at2 ON (a.id = at2.article_id) 
    INNER JOIN tags AS t2 ON (t2.id = at2.article_id AND t2.name = 'sports'); 
    

    假设tags.namearticles_tags.(article_id,tag_id)都有UNIQUE约束,你不应该需要一个DISTINCT查询修改。

    假设您已经定义了合适的索引,这种类型的查询往往比在GROUP BY解决方案上更好地优化MySQL。


再在评论你的后续问题,我会做这样的事情:

SELECT a.id, a.name, GROUP_CONCAT(t3.tag) AS all_tags 
FROM articles AS a 
INNER JOIN articles_tags AS at1 ON (a.id = at1.article_id) 
INNER JOIN tags AS t1 ON (t1.id = at1.tag_id AND t1.name = 'outdoors') 
INNER JOIN articles_tags AS at2 ON (a.id = at2.article_id) 
INNER JOIN tags AS t2 ON (t2.id = at2.article_id AND t2.name = 'sports'); 
INNER JOIN articles_tags AS at3 ON (a.id = at3.article_id) 
INNER JOIN tags AS t3 ON (t3.id = at3.article_id); 
GROUP BY a.id; 

这仍然只是发现有两个标签“户外”和“体育”的文章,但那么它进一步加入这些文章到全部它的标签。

这将返回多个行每个文章(每个标签一个),所以我们然后使用GROUP BY再次减少到每个文章一行。 GROUP_CONCAT()返回相应组中值的逗号分隔列表。

+0

感谢您的解释...此外,是否有可能在此查询返回与匹配的文章相关的所有标签? – cardflopper 2009-12-12 00:23:32

1

试试这个:

SELECT a1.id, a1.name FROM articles a1 
    JOIN tags t1 ON t1.name ='outdoors' 
    JOIN articles_tags at1 ON at1.article_id = a1.id AND at1.tag_id = t1.id 
    JOIN tags t2 ON t2.name = 'sports' 
    JOIN articles_tags at2 ON at2.article_id = a1.id AND at2.tag_id = t2.id