2010-07-16 193 views
18

我想查詢匹配所有給定的標籤集的對象。Mysql連接查詢多個「標籤」(多對多關係)匹配所有標籤?

基本上我希望用戶能夠添加越來越多的標籤來過濾或「縮小」他們的搜索結果,有點像newegg.com。

我的表結構是一個對象表,一個標籤表,以及一個MANY:MANY關係表ObjectsTags。所以我有一個連接查詢,像這樣:

SELECT * FROM Objects 
LEFT OUTER JOIN ObjectsTags ON (Objects.id=ObjectsTags.object_id) 
LEFT OUTER JOIN Tags ON (Tags.id=ObjectsTags.tag_id) 

我使用IN子句/條件,這樣的嘗試:

SELECT * FROM Objects 
LEFT OUTER JOIN ObjectsTags ON (Objects.id=ObjectsTags.object_id) 
LEFT OUTER JOIN Tags ON (Tags.id=ObjectsTags.tag_id) 
WHERE Tags.name IN ('tag1','tag2') 
GROUP BY Objects.id 

但我瞭解到,這個模擬了一系列的手術室,讓更多的標籤你向查詢中添加更多的結果,而不是像我希望的那樣縮小結果集。

我也嘗試做多等,其中條件,進行與運算在一起:

SELECT * FROM Objects 
LEFT OUTER JOIN ObjectsTags ON (Objects.id=ObjectsTags.object_id) 
LEFT OUTER JOIN Tags ON (Tags.id=ObjectsTags.tag_id) 
WHERE Tags.name LIKE 'tag1' 
AND Tags.name LIKE 'tag2' 
GROUP BY Objects.id 

但這不返回任何結果,因爲當結果被組合在一起的外部聯接Tags.name欄只包含「標籤1」,並而不是'tag2'。 'tag2'匹配的結果行​​被GROUPing「隱藏」。

如何匹配所有標籤以獲得我之後的「縮小」或「鑽取」效果?謝謝。

回答

26

用途:

SELECT * 
    FROM OBJECTS o 
    JOIN OBJECTSTAGS ot ON ot.object_id = o.id 
    JOIN TAGS t ON t.id = ot.tag_id 
    WHERE t.name IN ('tag1','tag2') 
GROUP BY o.id 
    HAVING COUNT(DISTINCT t.name) = 2 

你失蹤HAVING子句。

如果您只想要兩個標籤都存在的行,則不需要LEFT JOIN。

+1

如果您在OBJECTTAGS的一對列中沒有主鍵或唯一約束/索引以確保沒有重複(這些是誤報),則需要使用DISTINCT。 – 2010-07-16 18:05:05

+0

很好用!謝謝!從來沒有想過用這種方式與行計數。其他人的FYI:我在PHP中建立我的查詢,以便HAVING子句匹配我正在搜索的標籤數量,所以如果是('tag1','tag2','tag3'),我正在尋找HAVING COUNT(DISTINCT t.name)= 3,以確保他的結果具有所有標籤。 – thaddeusmt 2010-07-16 18:52:43

+0

真棒回答。謝謝 ! – 2013-11-17 00:43:45