2013-03-29 76 views
4

我有一個數據庫表如下:Findind的SQL解決基本集理論思想

╔═════════════════╦════════════╗ 
║ ADVERTISEMENTID ║ CATEGORYID ║ 
╠═════════════════╬════════════╣ 
║    1 ║ A   ║ 
║    1 ║ C   ║ 
║    2 ║ A   ║ 
╚═════════════════╩════════════╝ 

這基本上意味着:

  • 廣告#1屬於兩大類: A and C and
  • 廣告#2屬於一個類別:A

假設用戶傳遞了可能類別的參數(A,B,C)。這裏兩個廣告匹配,因爲一組可能的類別包含所有廣告#1的類別,並且可能類別的集合包含所有廣告#2的類別。

但是,如果用戶將另一組可能的類別作爲參數傳遞,如(A,D)。這裏只有廣告#2匹配和廣告#1不匹配,因爲一組可能的類別不包含所有的#1的類別。

現在我不確定如何在SQL中表達這種情況,即構建一個SQL查詢,該查詢從給定參數的可能類別ID的表中檢索不同的廣告ID。

任何人都可以請幫忙嗎?

回答

3

這個問題有很多可能的解決方案,但我使用的是通過篩選HAVING條款中的結果。

SELECT advertisementID 
FROM TableName 
GROUP BY advertisementID 
HAVING SUM(CASE WHEN CategoryID IN ('A','B','C') THEN 1 ELSE 0 END) > 0 AND 
     SUM(CASE WHEN CategoryID NOT IN ('A','B','C') THEN 1 ELSE 0 END) = 0 

簡要說明,

SUM(CASE WHEN CategoryID IN ('A','B','C') THEN 1 ELSE 0 END) > 0 

它這是什麼計數,鑑於名單上匹配的CategoryID。它應該從列表中至少有一個匹配。另外一個,

SUM(CASE WHEN CategoryID NOT IN ('A','B','C') THEN 1 ELSE 0 END) = 0 

它計數所有的CategoryID不給定的名單上匹配。這一次,這應該有一個值爲零,以便對結果進行過濾。

+0

非常感謝您的詳細回覆JW!實際上,我正在尋找更簡單的方法,可以將其移植到JPQL(Java Persitence API)中。你能不能簡單描述你暗示的其他可能的解決方案? – balteo

+0

@balteo其他解決方案正在使用'EXISTS','JOIN'。 –

+0

我可以知道我的答案中缺少什麼嗎?我的意思是沒有錯,但不接受它,但也許我需要一些解釋,所以我可以改善我的答案。 –

1

從@JW在sqlfiddle使用模式,另一種解決方案是:

SELECT matchacat.advertisementID 
FROM (select distinct advertisementID 
     from TableName 
     where CategoryID in ('A', 'D')) AS matchacat 
LEFT JOIN 
     (select distinct advertisementID 
     from TableName 
     where not CategoryID in ('A', 'D'))AS notmatch 
ON (matchacat.advertisementID = notmatch.advertisementID) 
WHERE notmatch.advertisementID is null 

所以,獲得一組廣告匹配至少一個貓的,然後得到一套具有非匹配的廣告貓並使用外連接從第一組中刪除第二組。

2

這就是所謂的集內集問題。我想找到任何類別的比賽最好的辦法是採取下列措施:

select ADVERTISEMENTID 
from t 
group by ADVERTISEMENTID 
having sum(case when categoryid = 'A' then 1 else 0 end) > 0 or 
     sum(case when categoryid = 'B' then 1 else 0 end) > 0 or 
     sum(case when categoryid = 'C' then 1 else 0 end) > 0 

換句話說,這是由advertisementid聚集,做每個類別值的獨立比較。陳述sum()正在計數它存在的數量。 or是說任何這些必須是真實的。

對於一個子集的關係,我增加一個條款來算非匹配:

select ADVERTISEMENTID 
from t 
group by ADVERTISEMENTID 
having (sum(case when categoryid = 'A' then 1 else 0 end) > 0 or 
     sum(case when categoryid = 'B' then 1 else 0 end) > 0 or 
     sum(case when categoryid = 'C' then 1 else 0 end) > 0 
     ) and 
     sum(case when categoryid in ('A', 'B', 'C') then 0 else 1 end) = 0 

我喜歡這種方法的原因是因爲它是相當傳神。如果我們改變了orand,那麼我們要求所有三類:

select ADVERTISEMENTID 
from t 
group by ADVERTISEMENTID 
having sum(case when categoryid = 'A' then 1 else 0 end) > 0 and 
     sum(case when categoryid = 'B' then 1 else 0 end) > 0 and 
     sum(case when categoryid = 'C' then 1 else 0 end) > 0 

如果我們想從該組至少兩場比賽,我們可以添加count(distinct)

select ADVERTISEMENTID 
from t 
group by ADVERTISEMENTID 
having (sum(case when categoryid = 'A' then 1 else 0 end) > 0 or 
     sum(case when categoryid = 'B' then 1 else 0 end) > 0 or 
     sum(case when categoryid = 'C' then 1 else 0 end) > 0 
     ) and 
     count(distinct categoryid) >= 2 

而且等等。

+0

我也在想這個,但你顯示的第一個查詢的問題是***它應該有所有***列表中存在的'categoryID'(*用戶不想要的,我認爲通過理解給出的例子*),這與'SELECT ADVERTISEMENTID FROM t WHERE CategoryID IN('A','B ','C')GROUP BY ADVERTISEMENTID HAVING COUNT(DISTINCT CategoryID)= 3',對吧? –

+1

@JW。 。 。謝謝。問題是尋找一個嚴格的子集關係。 –

+0

呵呵也許OP在主題'+ 1'上缺乏更好的解釋 –