2011-08-23 61 views
1

我有對象訓練,房間和老師。 培訓有0個或幾個房間。 培訓有0或幾位教師。sql multiple count

Table training (id,name,town)

Table training_room (id, id_training, id_room, enabled)

Table training_teacher (id, id_training, id_teacher, enabled)

我要鏈接 和鏈接使教師的數量誰屬於與使房間數目鎮培訓的列表。

我在哪裏可以寫入啓用字段的條件? 這是我查詢的開始。

SELECT training.id, 
     training.town , 
     COUNT (t_r.id_formation), 
     COUNT (t_t.id_formation) 
FROM training 
LEFT JOIN training_room t_r 
LEFT JOIN training_teacher t_t 
WHERE training.town ='X' 
GROUP BY training.id 

非常感謝。

+0

中有什麼'formation'表你查詢? –

+0

對不起,這是「訓練」(以法語形式:)) – Julien

回答

2

假設我已經理解了問題:

SELECT training.id, 
     training.town , 
     COUNT (distinct t_r.id), 
     COUNT (distinct t_t.id) 
FROM training t 
LEFT JOIN training_room t_r ON t.id = t_r.id_training AND t_r.enabled = 'true' 
LEFT JOIN training_teacher t_t ON t.id = t_t.id_training AND t_t.enabled = 'true' 
WHERE training.town ='X' 
GROUP BY training.id 
+0

實際上,在where子句中放置兩個'enabled'檢查會無意中將'LEFT'連接變爲'INNER'連接,因爲任何缺失的記錄都會返回'這些字段當然不會是'真'的。最好的解決方案是將這些條件放入相應聯接語句的「ON」子句中。 –

+0

完美。謝謝StevieG。我不能+1你的答案,因爲一個彈出窗口要求我登錄,而我已經登錄。 – Julien

+0

@Julien:當你有15個以下的代表點時,你無法註冊,但你可以[接受](http://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work)一個答案,如果它確實爲你工作。不過,我懷疑目前形式的這個特定答案會返回正確的結果。如果有2個房間和3個教師與培訓相匹配,那麼兩個COUNTs將返回6(2×3)用於該培訓。 –

0

這應該有助於

SELECT training.id, 
     training.town, 
     COUNT (SELECT t_r.id_training FROM training_room t_r WHERE t.id = t_r.id_training AND t_r.enabled = 'true') AS training_room_count, 
     COUNT (SELECT t_t.id_training FROM training_teacher t_t WHERE t.id = t_t.id_training AND t_t.enabled = 'true') AS training_teacher_count 
FROM training t 
WHERE training.town ='X' 

,或者你可以做(​​做整體同樣的事情):

SELECT training.id, 
     training.town , 
     COUNT (t_r.id_training) AS training_room_count, 
     COUNT (t_t.id_training) AS training_teacher_count 
FROM training t 
LEFT JOIN training_room t_r ON t.id = t_r.id_training 
LEFT JOIN training_teacher t_t ON t.id = t_t.id_training 
WHERE training.town ='X' 
    AND COALESCE(t_r.enabled, 'true') = 'true' 
    AND COALESCE(t_t.enabled, 'true') = 'true' 
GROUP BY training.id, training.town 
+0

我相信你在SQL Server中測試過你的腳本,至少是第二個包含'ISNULL'的腳本。 MySQL的等價物是'IFNULL',但你也可以使用兩個服務器產品都支持的'COALESCE'。 –

+0

我錯過了MySQL標籤,同時在看另一個問題,謝謝 – Seph

2

我會建議你不要像這樣加入你的餐桌。正如我在對StieveG的回答的評論中所說的那樣,通過以這種方式加入表格,您最終可以得到有時稱爲mini-Cartesian product的結果。這裏有一個說明解釋,以防萬一你需要它。

例如,你有2行中training_roomtraining匹配行,3行中training_teacher匹配相同training行。首先將會議室桌子連接在一起,結果,我們得到了兩排上述訓練。它們包含兩個不同的房間,但請記住它們也包含相同的訓練,重複。

爲什麼這很重要?因爲隨後加入的training_teacher完成而非僅針對訓練表,但針對加入的結果爲trainingtraining_room。它僅僅發生在連接條件僅包含training中的一列,但該列將取自上一次連接,不完全來自該表。

因此,您將與每個重複培訓進行匹配,並且每個人都會根據匹配教師的數量獲得另外三個培訓。

所以,最後一次培訓會產生6行,其中2個房間會重複3次,3個老師會重複兩次。因此,這兩個COUNT將返回6

一個可能的解決方案可能是簡單地改變計數的表達式是這樣的:

… 
COUNT (DISTINCT t_r.id), 
COUNT (DISTINCT t_t.id) 
… 

這不會阻止產生笛卡爾積的加入,但至少結果是一致的(提供的培訓就可以從來沒有重複的房間或教師)。

但是,如果我是你,我可能會解決這個問題不同,在子選擇分組並加入training表的子查詢的結果,就像這樣:

SELECT 
    t.id, 
    t.town, 
    IFNULL(tr.cnt) AS room_count, 
    IFNULL(tt.cnt) AS teacher_count 
FROM training AS t 

    LEFT JOIN (
    SELECT 
     id_training, 
     COUNT(*) AS cnt 
    FROM training_room 
    WHERE enabled = 'true' 
    GROUP BY id_training 
) AS tr ON t.id = tr.id_training 

    LEFT JOIN (
    SELECT 
     id_training, 
     COUNT(*) AS cnt 
    FROM training_teacher 
    WHERE enabled = 'true' 
    GROUP BY id_training 
) AS tt ON t.id = tt.id_training 

WHERE t.town = 'X'