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

标签 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

我做错了什么?

最佳答案

试试这个查询:

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_id 计算 amount 列的总和,但仅限于那些 user_id,也在 blocks 表中,并且 blocks.confirms 值大于 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           |
+ ------- + ------------ + ----------- + ------------- +

直连接(和 LEFT/RIGHT 外部连接)以这种方式工作,从第一个连接表中获取每条记录,并将该记录与另一个连接表中满足连接条件的所有行配对(合并) .

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

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 将计算上述结果集中所有 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
;

关于MySQL:带有 JOIN 的 SUM() 返回不正确的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18430162/

相关文章:

PHP 和 MySQL 查询 - 多条件

mysql 按 IN() Id 的顺序返回行

mysql - Grails 应用程序似乎持有对陈旧数据库连接的引用

python - Pandas dataframe.query 到 SQL 'LIKE' 而不使用引擎 ='python'

mysql - 如何获取早于 15 分钟前的最新条目?

php - 按左连接中的数据分组

mysql - 删除旧记录 - MySQL

MYSQL Left Join Or Get value from Subquery if the value exists 如果值存在

mysql - SQL 更新连接语法错误

mysql - 对非常大的 INNER JOIN SQL 查询进行分区