2013-08-25 88 views
3

我想爲表中的每個用戶提取一個SUM(),但是MySQL返回錯誤的值。MySQL:帶JOIN的SUM()返回不正確的值

這是它應該如何看(http://sqlfiddle.com/#!2/7b988/4/0

user amount 
110  20.898319244385 
114  43.144836425781 
115  20.487638473511 
116  26.07483291626 
117  93.054000854492 

但是,這是它的外觀(http://sqlfiddle.com/#!2/7b988/2/0

user amount 
110  167.186554 
114  129.434509 
115  143.413469 
116  208.598663 
117  744.432007 

這是查詢我試圖運行:

SELECT 
    blocks.user_id, 
    SUM(payout_history.amount) as amount 
FROM blocks 
LEFT JOIN payout_history 
ON blocks.user_id = payout_history.user_id 
WHERE confirms > 520 
GROUP BY blocks.user_id 

我在做什麼錯?

回答

7

嘗試此查詢:

SELECT bl.user_id, SUM(ph.amount) PAIDOUT 
FROM (
    SELECT distinct blocks.user_id 
    FROM blocks 
    WHERE confirms > 520 
) bl 
LEFT JOIN payout_history ph 
ON bl.user_id = ph.user_id 
GROUP BY ph.user_id 
; 

SQLFiddle - >http://sqlfiddle.com/#!2/7b988/48



---編輯---查詢是如何工作的(或解釋,而爲什麼你的查詢不起作用)----

看着預期的結果,似乎查詢應計算出每個user_idamount列的總和,但僅限於那些user_id,那也是在blocks表,並有blocks.confirms值grather超過520
一個簡單連接(也左外連接)可在這種情況下無法正常工作,因爲blocks表可以包含多條記錄爲同一user_id,爲例如,對於僅user_id=110返回行的查詢給出了以下的結果:

SELECT * 
FROM blocks 
WHERE confirms > 520 
     AND user_id = 110; 

+ ------- + ------------ + ----------- + ------------- + 
| id  | user_id  | reward  | confirms  | 
+ ------- + ------------ + ----------- + ------------- + 
| 0  | 110   | 20.89832115 | 521   | 
| 65174 | 110   | 3.80357075 | 698   | 
| 65204 | 110   | 4.41933060 | 668   | 
| 65218 | 110   | 4.69059801 | 654   | 
| 65219 | 110   | 4.70222521 | 653   | 
| 65230 | 110   | 4.82805490 | 642   | 
| 65265 | 110   | 5.25058079 | 607   | 
| 65316 | 110   | 6.17262650 | 556   | 
+ ------- + ------------ + ----------- + ------------- + 

的straigh加入(和左/右外聯接)工作在這種方式中,需要從第一joinded表中的每個記錄,並且配對這記錄(組合它)與來自另一個連接表中的所有行,並滿足連接條件。

在我們的情況下,左連接產生以下結果集:

SELECT * 
FROM blocks 
LEFT JOIN payout_history 
ON blocks.user_id = payout_history.user_id 
WHERE confirms > 520 
    AND blocks.user_id = 110; 
+ ------- + ------- + ----------- + -------- + --- + ------- + ----------- + 
| id  | user_id | reward  | confirms | id | user_id | amount  | 
+ ------- + ------- + ----------- + -------- + --- + ------- + ----------- + 
| 0  | 110  | 20.89832115 | 521  | 1 | 110  | 20.898319 | 
| 65174 | 110  | 3.80357075 | 698  | 1 | 110  | 20.898319 | 
| 65204 | 110  | 4.41933060 | 668  | 1 | 110  | 20.898319 | 
| 65218 | 110  | 4.69059801 | 654  | 1 | 110  | 20.898319 | 
| 65219 | 110  | 4.70222521 | 653  | 1 | 110  | 20.898319 | 
| 65230 | 110  | 4.82805490 | 642  | 1 | 110  | 20.898319 | 
| 65265 | 110  | 5.25058079 | 607  | 1 | 110  | 20.898319 | 
| 65316 | 110  | 6.17262650 | 556  | 1 | 110  | 20.898319 | 
+ ------- + ------- + ----------- + -------- + --- + ------- + ----------- + 

,現在如果我們添加SUM(amount) .... GROUP BY user_id,MySQL將calucate從上面的結果集所有amount值的總和(8行* 20.898 =〜167.184)

SELECT blocks.user_id, sum(amount) 
FROM blocks 
LEFT JOIN payout_history 
ON blocks.user_id = payout_history.user_id 
WHERE confirms > 520 
    AND blocks.user_id = 110 
GROUP BY blocks.user_id; 
+ ------------ + ----------------- + 
| user_id  | sum(amount)  | 
+ ------------ + ----------------- + 
| 110   | 167.186554  | 
+ ------------ + ----------------- + 



當你在這種情況下,加入並沒有給我們想要的結果看 - 我們需要命名爲a semi join的東西 - 下面是不同的變種,半連接,給他們試一試:

SELECT bl.user_id, SUM(ph.amount) PAIDOUT 
FROM (
    SELECT distinct blocks.user_id 
    FROM blocks 
    WHERE confirms > 520 
) bl 
LEFT JOIN payout_history ph 
ON bl.user_id = ph.user_id 
GROUP BY ph.user_id 
; 


SELECT ph.user_id, SUM(ph.amount) PAIDOUT 
FROM payout_history ph 
WHERE ph.user_id IN (
    SELECT user_id FROM blocks 
    WHERE confirms > 520 
) 
GROUP BY ph.user_id 
; 

SELECT ph.user_id, SUM(ph.amount) PAIDOUT 
FROM payout_history ph 
WHERE EXISTS (
    SELECT 1 FROM blocks bl 
    WHERE bl.user_id = ph.user_id 
     AND bl.confirms > 520 
) 
GROUP BY ph.user_id 
; 
+0

這似乎是我以後的解決方案。 你能解釋一下,所以我可以理解它爲什麼有效嗎? – Tyler

+3

@roboreb我附加了一個解釋爲什麼你的查詢不起作用。 – krokodilko