MySQL:带有JOIN的SUM()返回不正确的值

时间:2013-08-25 14:44:27

标签: mysql sql join sum

我正在尝试为表中的每个用户获取一个SUM(),但是MySQL返回了错误的值。

它的外观(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

我做错了什么?

2 个答案:

答案 0 :(得分:8)

尝试此查询:

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



---编辑---解释查询是如何工作的(或者说你的查询无效的原因)----

查看预期结果时,查询似乎应为每个amount计算user_id列的总和,但仅针对那些user_id的{​​{1}}列。blocks }表,并且{* 1}}值比520更高。
在这种情况下,简单连接(也称为左外连接)不起作用,因为blocks.confirms表可以包含同一blocks的许多记录,例如仅返回user_id行的查询得出以下结果:

user_id=110

straigh join(和LEFT / RIGHT外连接)以这种方式工作,它从第一个连接表中获取每个记录,并将此记录(组合它)与来自另一个连接表的所有行配对,以满足连接条件。

在我们的例子中,左连接产生以下结果集:

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           |
+ ------- + ------------ + ----------- + ------------- +

现在如果我们添加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 | + ------- + ------- + ----------- + -------- + --- + ------- + ----------- + ,MySql将从上面的结果集中计算所有SUM( amount ) .... GROUP BY user_id值的总和(8行* 20.898 = ~167.184)

amount



正如你在这种情况下看到的那样,连接不会给我们带来预期的结果 - 我们需要一些名为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

答案 1 :(得分:0)

这是旧文章,但我认为这可以帮助其他人

sum

内使用不同的内容
SELECT 
    blocks.user_id, 
    SUM(distinct 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

请参考@jerome wagner的答案

MYSQL sum() for distinct rows