【问题标题】:MySQL SUM outputs wrong value in a query consisting multiple joinsMySQL SUM 在包含多个连接的查询中输出错误值
【发布时间】:2012-07-22 00:00:12
【问题描述】:

我正在使用以下查询获取有关这些表的信息,但是 deferhit 和 deferdamage SUM 值正在乘以第一个连接的行号的行数。

表'战斗':

battle_id   city_id     attacker    defender    battle_time 
1           07          6           0           1342918014

表'battlehits':

battle_id   family_id   user_id     hits    damage 
1           0           0           1000    50000
1           6           15          108     3816
1           6           2           81  2046
1           6           1           852 1344

MySQL 查询

SELECT b.battle_id, b.city_id, b.attacker, b.defender, b.battle_time,
SUM(COALESCE(bh1.damage,0)) AS attackerdamage, SUM(COALESCE(bh2.damage,0)) AS defenderdamage,
SUM(COALESCE(bh1.hits,0)) AS attackerhit, SUM(COALESCE(bh2.hits,0)) AS defenderhit
FROM battles AS b
LEFT JOIN battlehits AS bh1 ON b.attacker = bh1.family_id
LEFT JOIN battlehits AS bh2 ON b.defender = bh2.family_id
WHERE b.battle_id=1
GROUP BY b.battle_id LIMIT 1

查询结果如下:

battle_id   city_id     attacker    defender    battle_time     attackerdamage  defenderdamage  attackerhit     defenderhit 
1           07          6           0           1342918014      7206            150000          1041            3000

正如您在表数据中看到的,defenderhit 和 deferdamage SUM 值应该是 1000 和 50000,但它们乘以 3。 我在这里做什么?有什么问题?

提前致谢。

【问题讨论】:

    标签: mysql join sum


    【解决方案1】:

    在 group by/sum 之前,您将获得三行。战斗命中的三个攻击者行中的每一行都有一个行。这些中的每一个都与来自战斗命中的相同防御者行配对,导致防御者数据增加三倍。要看到这一点,请删除 group by 和 limit 子句并取出 sum()s。您实际上是在创建所有防御者 X 所有攻击者的叉积,然后求和。

    这显示了包含重复后卫数据的三行。这是对一对多关系而不是一对一关系进行联接的结果。

    SELECT b.battle_id, b.city_id, b.attacker, b.defender, b.battle_time,
    COALESCE(bh1.damage,0) AS attackerdamage, COALESCE(bh2.damage,0) AS defenderdamage,
    COALESCE(bh1.hits,0) AS attackerhit, COALESCE(bh2.hits,0) AS defenderhit
    FROM battles AS b
    LEFT JOIN battlehits AS bh1 ON b.attacker = bh1.family_id
    LEFT JOIN battlehits AS bh2 ON b.defender = bh2.family_id
    WHERE b.battle_id=1;
    

    输出:

    battle_id   city_id attacker    defender    battle_time attackerdamage  defenderdamage  attackerhit defenderhit
    1   7   6   0   1342918014  3816    50000   108 1000
    1   7   6   0   1342918014  2046    50000   81  1000
    1   7   6   0   1342918014  1344    50000   852 1000
    

    您需要将其拆分为单独的查询。一个用于攻击者的总和,另一个用于防御者的总和。

    【讨论】:

    • 我明白了。感谢您的答复。我想我会使用单独的子查询。然而,我有一个问题。使用子查询来获取这样的查询的总和值是否很好,或者我应该使用单独的查询?性能上有什么区别?
    • 我的猜测是子查询会稍微快一些,因为战斗表上 where 子句的结果可以共享。但这实际上取决于查询优化器。如果速度很关键,我会用两种方式编写它并使用解释,或者不寒而栗:),甚至做一些计时。但我怀疑如果您在battle_id 和family_id 上有索引,差异会很大。
    • 好吧,我将使用子查询。谢谢你的信息。
    【解决方案2】:

    您可以使用模拟不同行的总和

    (SUM(t.field_to_sum) / COUNT(t.primary_key) * COUNT(DISTINCT t.primary_key))
    

    【讨论】:

    • 感谢您的回复,但我会单独询问。无论如何,谢谢。
    猜你喜欢
    • 2020-03-17
    • 1970-01-01
    • 2015-07-18
    • 1970-01-01
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多