2010-09-09 165 views
2

我在我的數據庫中有兩個表:項目和類別。 項目可以是活動的或不活動的,並且具有與類別表中的記錄的id相關的categoryID。mysql左連接問題與SUM和WHERE子句

我想

所以我的目標是執行一個查詢,以顯示所有類別,以有效項目的該類別的總成本返回的東西看起來像這樣:

+--------+------------+---------------+ 
    | id  | cat_name | total_cost | 
    +--------+------------+---------------+ 
    |  1 | cat 1  | 12   | 
    |  2 | cat 2  | 0    | 
    |  3 | cat 3  | 45   | 
    +--------+------------+---------------+ 

我的第一個查詢:

SELECT a.*, 
    SUM(b.cost) AS total_cost 
    FROM categories a LEFT JOIN items b 
    ON(a.id = b.category_id) 
    GROUP BY a.category_name 

工作正常,但它返回NULL項而不是0,並使用所有項目,無論active/in主動:

+--------+------------+---------------+ 
    | id  | cat_name | total_cost | 
    +--------+------------+---------------+ 
    |  1 | cat 1  | 44   | 
    |  2 | cat 2  | NULL   | 
    |  3 | cat 3  | 87   | 
    +--------+------------+---------------+ 

我的第二個查詢不會忽略的NULL值:

SELECT a.*, 
    SUM(IF(b.cost IS NULL, 0, b.cost)) AS total_cost 
    FROM categories a LEFT JOIN items b 
    ON(a.id = b.category_id) 
    GROUP BY a.category_name 

和原來像這樣:

+--------+------------+---------------+ 
    | id  | cat_name | total_cost | 
    +--------+------------+---------------+ 
    |  1 | cat 1  | 44   | 
    |  2 | cat 2  | NULL   | 
    |  3 | cat 3  | 87   | 
    +--------+------------+---------------+ 

因此,在我很小的無用的大腦我嘗試下面的查詢,添加表b上的WHERE子句,其中活動必須= 1(真)

SELECT a.*, 
    SUM(IF(b.cost IS NULL, 0, b.cost)) AS total_cost 
    FROM categories a LEFT JOIN items b 
    ON(a.id = b.category_id) 
    WHERE b.active = 1 
    GROUP BY a.category_name 

和我得到以下幾點:

+--------+------------+---------------+ 
    | id  | cat_name | total_cost | 
    +--------+------------+---------------+ 
    |  1 | cat 1  | 12   | 
    |  3 | cat 3  | 45   | 
    +--------+------------+---------------+ 

所以你可以SE,我想回類別的全部範圍,即使右表中沒有返回匹配結果...任何花費一百萬虛酷點?

回答

6

用途:

SELECT c.id, 
      c.cat_name, 
      COALESCE(SUM(i.cost), 0) AS total_cost 
    FROM CATEGORIES c 
LEFT JOIN ITEMS i ON i.category_id = c.category_id 
       AND i.active = 1 
GROUP BY c.id, c.cat_name 
+0

它的工作原理,沒有問題。但在MySQL中,您不需要通過'cat_name'進行分組。 'id'就足夠了。如果你希望它更有效並且符合SQL標準,那麼在列表達式中使用'max(c.cat_name)'或類似的group by函數。 – 2010-09-09 21:58:50

+0

@Imre L:假設可能,如果有兩個或多個cat_name值與同一個id相關聯,則使用MAX將隱藏。關於在組中定義列沒有任何非標準,因爲它們沒有集合函數,並且假設id值是唯一的,那麼它是個人選擇(儘管MAX/etc意味着可能有重複)。 – 2010-09-09 22:23:31

+0

布拉沃先生 - 您可以隨身攜帶儘可能多的想象中的酷點,爲自己在包上大放異彩。 我需要對這個合併聲明做一些閱讀以充分理解發生了什麼。 – Beans 2010-09-10 00:03:39

1

試試這個:

SELECT a.*, 
    SUM(Case B.Active When 1 Then b.cost else 0 End) AS total_cost 
    FROM categories a 
     LEFT JOIN items b 
     ON b.category_id = a.id 
    GROUP BY a.category_name 

或本:

SELECT a.*, SUM(b.cost) AS total_cost 
    FROM categories a 
     LEFT JOIN items b 
     ON b.category_id = a.id 
      And B.Active = 1 
    GROUP BY a.category_name 
+0

你也完全膽大包天,賺取一個極大想象冷靜點 - 謝謝你。這些都有很大的意義,當然還有工作。你有什麼智慧來說明爲什麼一種方法比另一種更好?從可讀性的角度來看,我發現即使它比較冗長,也很容易理解第一個查詢。 – Beans 2010-09-09 23:56:19

+0

此外,第一個爲total_cost返回空值而不是零,但這是一個簡單的修復。我認爲第二個應該有b.active = 1,而不是b.cost = 1 – Beans 2010-09-10 00:05:09

+0

啊,是的,錯字... b.active它應該是! – 2010-09-10 00:28:03