【问题标题】:Wrong result using sum at MySQL在 MySQL 中使用 sum 的错误结果
【发布时间】:2013-04-19 21:10:33
【问题描述】:

我有一个包含大量数据的视图。我可以使用子查询得到这个结果(数据是好的和优化的):

+------------+
| attendance |
+------------+
|        319 |
|        102 |
|        598 |
|        113 |
|          6 |
|        279 |
|        366 |
|        146 |
|        669 |
|        205 |
|        123 |
+------------+

下次某些用户更新数据时,它会显示:

+------------+
| attendance |
+------------+
|        319 |
|        102 |
|        598 |
|        113 |
|          7 |
|        279 |
|        253 |
|        146 |
|        669 |
|        561 |
|        123 |
+------------+

没关系,因为更新信息的用户是之前有 6 个出席的用户。

但是当我将这些数据用作临时表然后我制作时,问题就来了:

 SELECT SUM(attendance) AS total FROM ( /* Subquery returning the above table */)

因为它返回(首先一个用户有 6 个出席):

+-------+
| total |
+-------+
|  3169 |
+-------+

还有 7:

+-------+
| total |
+-------+
|  3128 |
+-------+

什么时候应该是3170!!!

想法?

编辑 1:粘贴完整的查询。

SELECT SUM(att_member) AS total
FROM
    (SELECT attendance AS att_member
     FROM
         (SELECT id_branch_channel, id_member, attendance, TIMESTAMP, id_event
          FROM view_event_attendance
          WHERE id_event = 782
          ORDER BY TIMESTAMP DESC) AS temptable
     GROUP BY 
              id_member) AS total_attendance_temp

编辑 2:粘贴我从这里获得的查询帮助

Select only last value using group by at mysql

这是视图的架构。

【问题讨论】:

  • 要么是 MySQL 错误,要么是子查询有问题。我打赌子查询:) 你能发布吗?
  • 除非查询非常庞大/丑陋,你能在这里展示它们吗?
  • 另请注意,您帖子中的值列表与第 5 行的 6 和 7 不同。第 7 行在第一个列表中也有 366,在第二个列表中有 253,第 10 行有 205第一个列表和第二个列表中的 561 个。
  • @EdGibbs 是的,你是对的。我没有注意到这一点。然后我将搜索子查询...
  • @AbrahamSustaita - 感谢您的链接;现在我明白你为什么需要子查询了:)顺便说一句,在这个问题上做得很好!

标签: mysql sum


【解决方案1】:

让我们剖析查询,好吗?

我假设 view_event_attendance 对参加活动的每个与会者(成员)都有一个记录。 id_event 是该事件的 FK,id_member 是与会者的 FK。您的内部选择为您提供了参加活动 #782 的所有成员的有序列表

SELECT id_branch_channel, id_member, attendance, TIMESTAMP, id_event
FROM view_event_attendance
WHERE id_event = 782
ORDER BY TIMESTAMP DESC

到目前为止,太棒了。现在你将这个查询包装在另一个中:

SELECT attendance AS att_member
FROM (subquery)
GROUP BY id_member

在大多数 SQL dialetcs 中,这只是一个语法错误。 MySQL 允许这样做,但结果可能不是您想要的。您将获得参加所述活动的每个 id_member 的 attendance 列。您实际上可能期望的是出席人数的总和,但我在您的问题中没有这么说。在任何情况下,每个选定的字段都应该在您的 GROUP BY 子句中或使用聚合函数,例如

SELECT SUM(attendance) AS att_member
FROM (subquery)
GROUP BY id_member

SELECT attendance AS att_member
FROM (subquery)
GROUP BY id_member, attendance

话虽如此,我认为不需要使用子查询来开始。假设您想获得上述 SUM,您可以将其重新表述为单个 SQL 查询:

SELECT SUM(attendance) AS att_member
FROM view_event_attendance
WHERE id_event = 782
GROUP BY id_member

如果你想要总数,你可以简单地省略GROUP BY 子句,留下这个:

SELECT SUM(attendance) AS att_member
FROM view_event_attendance
WHERE id_event = 782

如果这没有按预期工作,请更详细地描述您在 view_event_attendance 中实际存储的内容,以及您希望第二个查询计算的内容。

【讨论】:

  • 感谢您的帮助!但我想如果你read the other link I pasted 那么你就会明白我为什么需要子查询。我发现了,但是我的错误。再次阅读那个链接,我记得我从来没有在那里使用过答案,所以这样做可以修复它。那里有cmets吗?看看我在这里给出的答案。再次感谢:)
【解决方案2】:

正如@EdGibbs 所注意到的,子查询返回了错误的结果(我没有注意到)。因此,我再次阅读了我的代码和the answer to the other question I make reference,现在事情可以正常工作了,这样做:

SELECT SUM(att_member) AS total
FROM
    (SELECT attendance AS att_member
     FROM
         (SELECT 
            id_branch_channel, 
            id_member, 
            substring(max(concat(from_unixtime(timestamp),attendance)) from 20) as attendance, 
            timestamp, 
            id_event
          FROM view_event_attendance
          WHERE id_event = 782
          GROUP BY id_event, id_member
          ORDER BY timestamp DESC) AS temptable
     ) AS total_attendance_temp

我做的唯一改变是:

  • 使用:substring(max(concat(from_unixtime(timestamp),attendance)) from 20) 作为出勤率,而不仅仅是出勤率。
  • 在第一个子查询中移动组。

所以问题不在于 MySQL 的 SUM 函数,而在于我的查询。

感谢大家花时间帮助我解决这个问题。您的建议有助于我得到答案。

【讨论】:

  • 我现在了解到您实际上是在依赖非标准行为。我明白你为什么要这样做,但现在看来是一个聪明的解决方案,事后看来可能是*最糟糕的事情*(tm)。
  • 那么您的建议是什么?让我解释一下我在做什么。我需要有出席活动的日志。因此,出于这个原因,我有一个只包含该信息的表:id_member_event(这是一个包含事件成员关系信息的表的 fk)、出勤率、时间戳。因此,在该表中,我可以多次参加某个活动(比如说,用户在大型活动中发送的次数超过了一次)
  • 在我的view_event_attendance我有整个事件的信息:id_event,id_member,_id_member_event,id_branch_channel,id_member_event_attendance,is_online,attendance,timestamp
  • 我想这一切都取决于您的内部视图实际上做了什么,以及是否有办法使用聚合函数(例如 MAX())来检索最新的出席人数。如果无法进一步优化它,您可能需要考虑对日志进行非规范化,以便父记录获得 latest_attendance 列。已经查看了两个子查询和对非标准行为的依赖,并且想象您的观点也很重要,我怀疑您的解决方案 a) 难以理解,b) 难以完整记录,c) 当底层桌子变大了。
  • @Hazzit 你能举个例子说明如何重新编码查询以使用 MAX()?
猜你喜欢
  • 2012-12-10
  • 2016-07-16
  • 2013-02-18
  • 1970-01-01
  • 2013-11-04
  • 1970-01-01
  • 2021-12-21
  • 1970-01-01
  • 2013-01-06
相关资源
最近更新 更多