当前位置: 首页 > 面试题库 >

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

南门新知
2023-03-14
问题内容

我正在尝试为表中的每个用户获取一个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

-–编辑—说明查询的工作方式(或更确切地说,为什么查询不起作用)----

从预期的结果看,查询似乎应该amount为每个user_id,但仅对于那些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 5.7 我想将联接表的结果串联到单列中。我使用包裹在函数中的函数。这是查询 列包含来自联接表的数据。数据已正确检索,但问题是列未转换为正确的JSON。 如您所见,最后有点“切”。 我也尝试过,但是现在它不能转换为正确的数组。它看起来像字符串太大,不适合列。有办法解决吗? 更新 问题必须出在不适合列的st大小中。我尝试从联接表中选择较少的列,并且它可以正常工作。也许有一

  • 问题内容: def size_of_dir(dirname): print(“Size of directory: “) print(os.path.getsize(dirname)) 是有问题的代码。dirname是一个目录,其中包含 130个 文件,每个文件约 1kb 。当我调用此函数时,它返回 4624 ,这 不是 目录的大小…为什么? 问题答案: 此值(4624B)代表的大小 文件 是 描

  • 本文向大家介绍MySQL查询返回TRUE为具有正值的行?,包括了MySQL查询返回TRUE为具有正值的行?的使用技巧和注意事项,需要的朋友参考一下 要为正值返回TRUE,为负返回FALSE,请使用MySQL IF()。让我们首先创建一个表- 使用插入命令在表中插入一些记录- 使用select语句显示表中的所有记录- 这将产生以下输出- 这是对具有正值的行返回true的查询- 这将产生以下输出-

  • 问题内容: 我在使用MySQL的“ GROUP_CONCAT”功能时遇到问题。我将使用一个简单的帮助台数据库来说明我的问题: 请注意,该帮助台数据库有两个票证,每个票证都有两个解决方案条目。我的目标是使用SELECT语句创建数据库中所有故障单及其对应解决方案条目的列表。这是我正在使用的SELECT语句: 上面的SELECT语句的问题在于它仅返回一行: 请注意,它正在返回票证1的信息以及票证1和票证

  • 问题内容: 很抱歉,我只学习了PHP和MySQL,已经搜索了一个多星期,但是没有找到任何答案。 我创建了一个简单的财务脚本,该表如下所示: 我想要这样的结果 有人可以帮助我解决我的问题吗? 谢谢 问题答案: 正如@Quassnoi指出的那样,这对于MySQL来说不是很有效。我尝试使用怪胎连接而不是子查询,因为内部查询本身就可以使用。 编辑 对此引起了一些兴趣,发现连接版本的速度是@Quassnoi

  • 我正在使用postgis计算两个地理坐标之间的距离。 它返回给我53536.743496517米,大约等于54公里,但实际距离是103公里,我通过http://boulter.com/gps/distance/ 我在询问中是否做错了什么?