MySQL:带有 JOIN 的 SUM() 返回不正确的值
Posted
技术标签:
【中文标题】MySQL:带有 JOIN 的 SUM() 返回不正确的值【英文标题】:MySQL: SUM() with JOIN returns incorrect values 【发布时间】:2013-08-28 02:50:34 【问题描述】:我正在尝试为表中的每个用户获取 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
我做错了什么?
【问题讨论】:
【参考方案1】:试试这个查询:
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
表中,并且具有@987654327 @值大于 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 |
+ ------- + ------------ + ----------- + ------------- +
直线连接(和左/右外连接)以这种方式工作,它从第一个连接表中获取每条记录,并将这条记录与另一个连接表中的所有行配对(组合)以满足连接条件. 在我们的例子中,左连接产生以下结果集:
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
;
【讨论】:
这似乎是我所追求的解决方案。你能解释一下,以便我理解它为什么有效吗? @roboreb 我附加了一个解释为什么你的查询不起作用。【参考方案2】:这是一个旧帖子,但我认为这可以帮助其他人
在sum
中使用 distinctSELECT
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
【讨论】:
在 sum 中添加 distinct 但如果数量相同则不包括在内。 @JohnS 链接的答案确实解决了相同金额的问题以上是关于MySQL:带有 JOIN 的 SUM() 返回不正确的值的主要内容,如果未能解决你的问题,请参考以下文章
使用带有 SUM 和 GROUP BY 的完整 JOIN 避免重复条目
使用 Redshift 数据库时,SQL Join 或 SUM 返回太多值