2008-10-02 52 views
10

假設我有一個帶兩列的「標籤」表:tagidcontentid。每一行代表分配給一段內容的標籤。我想要一個查詢,這將使我的每一條內容被標記爲tagids 334,338的內容識別,和342SQL查詢:在幾行而不是子查詢中模擬「AND」

「易」的方式來做到這將是():

select contentid from tags where tagid = 334 and contentid in (
    select contentid from tags where tagid = 338 and contentid in (
     select contentid from tags where tagid = 342 
    ) 
) 

但是,我的直覺告訴我,有一個更好,更快,更可擴展的方法來做到這一點。例如,如果我需要找到12個標籤的交集?這很快就會變得可怕。有任何想法嗎?

編輯:原來這也包括在this excellent blog post

回答

24
SELECT contentID 
FROM tags 
WHERE tagID in (334, 338, 342) 
GROUP BY contentID 
HAVING COUNT(DISTINCT tagID) = 3 


--In general 
SELECT contentID 
FROM tags 
WHERE tagID in (...) --taglist 
GROUP BY contentID 
HAVING COUNT(DISTINCT tagID) = ... --tagcount 
+0

就是這樣。雖然如果tagid,contentid是唯一的,那麼COUNT中可能不需要DISTINCT(DISTINCT tagID) – tzot 2008-10-02 18:44:04

+0

非常聰明的解決方案,但它需要對我們安裝的SQL2000進行調整。如果沒有select子句中的聚合,我們不能使用「having」。很容易解決,雖然。 – 2008-10-02 18:49:48

+0

這將工作在MySQL和Oracle? – 2008-10-02 19:00:50

1

唯一的替代辦法,我能想到的是:

select a.contentid from tags a 
inner join tags b on a.contentid = b.contentid and b.tagid=334 
inner join tags c on a.contentid = c.contentid and c.tagid=342 
where a.tagid=338 
-1

SQL的什麼類型的? MS SQL Server,Oracle,MySQL?

在SQL Server不會將此等同於:

select contentid from tags where tagid IN (334,338,342) 
0

我不知道這是更好,但它可能是更容易維護

select contentid from tags where tagid = 334 
intersect 
select contentid from tags where tagid = 338 
intersect 
select contentid from tags where tagid = 342 

你必須建立它動態的,這不會像你原來的解決方案一樣糟糕。

2

這是一個解決方案,它比我在一個非常大的對象和標籤數據庫上的工作速度快得多。這是一個三標籤交叉點的例子。這只是衆多連鎖加盟的對象變量表(objtags)來表示同一個對象,並規定了WHERE子句中的標籤ID:

SELECT w0.objid 

FROM  objtags t0 
INNER JOIN objtags t1 ON t1.objid=t0.objid 
INNER JOIN objtags t2 ON t2.objid=t1.objid 

WHERE t0.tagid=512 
    AND t1.tagid=256 
    AND t2.tagid=128 

我不知道爲什麼這樣運行速度更快。它受到MusicBrainz服務器搜索代碼的啓發。在Postgres中做這件事,我通常比HAVING COUNT(...)解決方案的速度快8-10倍。