2009-12-09 72 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