昨天运营提了个需求,要拉下每个玩家在前天一天内的消耗钻石数量,想着很简单,就是根据玩家id group by分组下,然后用sum函数求和就好了。因为涉及到公司隐私,故将钻石消耗表简化为如下的结构

图片描述

sql语句也就很简单了,如下所示。

select sum(consume_num) as total_consume,role_id,server_id from gold_consume where timestamp>=开始时间 and timestamp<=结束时间 group by role_id;

结果奇怪的事情出现了,不仅total_consume出现了奇怪的数字,还有很多role_id和server_id为空,但total_consume有值的情况,截图如下。

clipboard.png

先是怀疑记的日志里可能存在role_id或者server_id为空的,于是去掉sum来试试,发现并没有出现空的情况,sql如下。

select consume_num as total_consume,role_id,server_id from gold_consume where timestamp>=开始时间 and timestamp<=结束时间 group by role_id;

接着怀疑是不是存在一个role_id对应多个server_id的情况,于是改group by role_id,server_id,再执行一次,查看结果,发现问题并没有解决,sql如下。

select sum(consume_num) as total_consume,role_id,server_id from gold_consume where timestamp>=开始时间 and timestamp<=结束时间 group by role_id,server_id;

最后仔细看了下表结构,猜想是不是因为consume_num的字段类型是varchar,不是数字,记日志的时候多了些空格造成的?于是尝试给consume_num强转为int试试,sql如下。

select sum(cast(consume_num as DECIMAL)) as total_consume,role_id,server_id from gold_consume where timestamp>=开始时间 and timestamp<=结束时间 group by role_id;

执行后发现问题得到解决,无奈脸~
后面也谷歌了这个问题,想知道下是什么原因,但看了一圈,也没找到很清晰能说服自己的理论(只找到一个说是mysql sum的时候对数据量小的时候是可以隐式转化成int求和的,但数据量大了,就不一定了)心塞。所以如果有哪位大佬知道这个问题的原理的,求赐教,跪谢。


叶子
1 声望0 粉丝