2011-06-27 61 views
2

我有幾個表在我的應用程序中使用。一個維護一個產品列表,另一個維護對這些項目的評論,另一個包含這些項目的星級評分,最後一個購買這些項目。我的表是這個樣子:需要查詢幫助 - 聚合和多個連接

tbl_item: 
--------- 
id  INT (primary key) 
name VARCHAR (product name) 

tbl_comment: 
------------ 
id   INT (primary key) 
item_id  INT (foregin key -> tbl_item.id) 
commenttext VARCHAR 

tbl_rating: 
----------- 
id   INT (primary key) 
item_id  INT (foreign key -> tbl_item.id) 
rating  DOUBLE 

tbl_purchases: 
-------------- 
id   INT (primary key) 
item_id  INT (foreign key -> tbl_item.id) 

我想執行返回下面的查詢:

* The design ID 
* The average rating 
* The number of comments 
* The number of purchases 

我有一些與此類似,但它返回不正確的數據:

SELECT d.id , 
     COUNT(tbl_purchases.id) AS purchase_count, 
     COUNT(tbl_comment.id) AS comment_count, 
     AVG(tbl_rating.rating) AS item_rating, 
    FROM tbl_item d 
    LEFT JOIN tbl_purchases ON tbl_purchases.item_id = d.id 
    LEFT JOIN tbl_comment ON tbl_comment.item_id = d.id 
    LEFT JOIN tbl_rating ON tbl_rating.id = d.id 
    GROUP BY d.id; 

我發現我的COUNT()列爲兩列返回相同的值,這肯定是不正確的。很明顯,我在我的連接或GROUP BY中做錯了事,但我不完全確定是什麼。我是一個Java人,而不是一個SQL人,所以我不確定這個SELECT語句出了什麼問題。

任何人都可以幫我構建這個查詢嗎?有沒有辦法通過這種方式跨多個不同的表執行這個聚合查詢?謝謝!!

+0

計數將返回相同,因爲它計數最終結果集(它不關心它是否爲空)。如果你想每桌單獨計數,我建議看看子查詢。 – Limey

+0

您也可以設置變量,然後用case語句手動跟蹤每個表的總計。 – Limey

+0

你能給我一個例子,說明如何用子查詢來完成這個任務嗎?就像我說的,我是一個Java人,並且對SQL沒有太多的經驗。 – Shadowman

回答

5

試試這個:

SELECT d.id , 
     COALESCE(t.purchase_count,0) as purchase_count, 
     COALESCE(c.comment_count,0) as comment_count, 
     r.item_rating, 
    FROM tbl_item d 
    LEFT JOIN (SELECT item_id, COUNT(1) as purchase_count from tbl_purchases group by item_id) as t on t.item_id = d.id 
    LEFT JOIN (SELECT item_id, COUNT(1) as comment_count from tbl_comment group by item_id) as c ON c.item_id = d.id 
    LEFT JOIN (SELECT item_id, AVG(rating) as item_rating from tbl_rating group by item_id) as r ON r.item_id = d.id; 
+0

打我吧:) +1 – Randy

+0

我試了@Seth Robertson的答案,它的工作,但表現很糟糕。這個答案效果很好。數量級更快。謝謝! – Shadowman

+0

作爲一個經驗法則,在連接之前而不是在連接之後實現一個組總是最好的。如果你考慮數據庫必須做什麼來執行一個組和一個連接,你會明白爲什麼這是真的(我沒有足夠的空間來提供解釋:))。 – Gareth

0

這將取決於上有所DB你使用的是什麼,但在PostgreSQL的這種失控的工作:

SELECT d.id , p.count, c.count, AVG(I.rating) 
     FROM tbl_item d 
     JOIN (SELECT count(id), item_id as id from tbl_purchases) as P 
    USING (id) 
     JOIN (SELECT count(id), item_id as id from tbl_comment) as C 
    USING (id) 
LEFT JOIN tbl_rating as I 
     ON tbl_rating.id = d.id 
    GROUP BY d.id 
; 
1

使用count(distinct(tbl_purchases.id))應該解決您的問題沒有更多複雜的查詢(但也是正確的)他人提供的查詢。

+0

這就像一個魅力!謝謝! – Shadowman

+0

我已經運行這個查詢,它工作得很好。但是,我注意到性能是可怕的。其他答案是否會導致查詢更快?有什麼方法可以獲得更好的表現嗎? – Shadowman