2011-03-15 42 views
5

我再次發佈這個問題,因爲我認爲我上次可能沒有很好地描述它,而我認爲工作的解決方案不是。MySQL:多對多加入不存在的地方

我有3個表格:項目,服務和建議。建議提供了項目和服務之間的多對多關係,即建議書中的每一行都有一個project_id和一個service_id。

假設有1000個項目和5個服務。我希望我的建議表中不會超過5000條記錄,但幾乎肯定會少一些(即一些項目沒有服務建議)。因此,對於項目#1,如果已建議所有5個服務,我會看到建議表像5行:

project_id service_id 
1   1 
1   2 
1   3 
1   4 
1   5 

我所試圖做的是建立一個查詢,顯示我哪些項目不推薦所有5種服務,以及這些服務是哪些。假設項目#1只有推薦的前3個服務;我的查詢顯示哪些丟失的輸出可能如下所示:

project_id service_id 
1   4 
1   5 

謝謝!

+0

上一個問題:http://stackoverflow.com/questions/ 5169625/sql-join-three-tables-combined-inner-left-outer-join – JNK 2011-03-15 20:07:34

+2

如果你引用一個大於一個小時左右的在先問題,那麼包含一個鏈接是很好的,特別是當你說先前的答案沒有工作:) – JNK 2011-03-15 20:08:01

+1

確實,對不起!注意以備將來參考:P – David 2011-03-15 20:10:39

回答

5
Select P.project_id, S.service_id 
From Projects As P 
    Cross Join Services As S 
Where Not Exists (
        Select 1 
        From Recommendations As R1 
        Where R1.project_id = P.project_id 
         And R1.service_id = S.service_id 
        ) 

另一種變體,它應該在MySQL

現在我正確地讀出了問題的工作
Select P.project_id, S.service_id 
From Projects As P 
    Cross Join Services As S 
Where (P.project_id, S.service_id) Not In (
              Select R1.project_Id, R1.service_id 
              From Recommendations As R1 
              ) 
+0

@Joe Stefanelli - 實際上,從我讀到的內容來看,如果您不使用連接鍵的On子句或Where子句,它可以表現得像交叉連接一樣。 – Thomas 2011-03-15 20:12:59

+0

@Joe Stefanelli - 從文檔中,如果包含On子句或Where子句,基本上可以使用交叉聯接來表現爲內部聯接。沒關係。無論哪種方式,我都希望笛卡爾產品在沒有On或Where的情況下得到。 – Thomas 2011-03-15 20:14:19

+0

@托馬斯:我站了起來(好吧,我實際上坐着)正確。我將放棄評論和+1。 – 2011-03-15 20:15:25

2

更新。我仍然會使用外連接,但沒有子查詢這個時間:

SELECT p.project_id,s.service_id 
FROM projects p 
cross join services s 
LEFT OUTER JOIN recommendations r on r.project_id = p.project_id and r.service_id = s.service_id 
WHERE r.project_id IS NULL 
+1

現在修復了我的查詢。 – 2011-03-15 20:21:16

+0

謝謝艾克!你的工作也是如此,但我把它交給了托馬斯,因爲我首先開始使用他的解決方案。 +1 – David 2011-03-15 20:40:54

+0

沒問題。他們將返回完全相同的數據,但我建議您比較兩個查詢的性能。我希望我的速度至少快40%。 – 2011-03-15 20:57:41

1

一種相當簡單的方法是這樣的:

select project_id, count(*) 
from recommendations 
group by project_id 
having count(distinct service_id) < (select count(*) from services)