【问题标题】:MySQL numeric operation oddities - overflow?MySQL 数值运算的古怪之处 - 溢出?
【发布时间】:2015-04-27 04:17:00
【问题描述】:

在 MySQL 上的第一个查询有什么问题?

两列的预期答案是“718042670591505846”

SELECT 5002622390 + (5102 * 140737488355328) new_iid_hard_way,
     CAST(5002622390 + (5102 * POWER(2,47)) AS UNSIGNED) new_iid_WRONG_way

返回:

'718042670591505846','718042670591505792'

同时,此查询有效:

SELECT 5002622390 + (5102 * 140737488355328) new_iid_hard_way,
   5002622390 + (5102 * CAST(POWER(2,47) AS UNSIGNED)) new_iid_CORRECT_way

它返回: '718042670591505846', '718042670591505846'

我的预感是这是一个数据类型溢出/包装问题...但即使在 MySQL 5.6.15 上启用了严格模式,我也没有收到任何错误。

有趣的是,sqlfiddle 在所有 4 种情况下都会出错:

http://sqlfiddle.com/#!9/d1bb6/1

返回 718042670591505800

这是溢出问题吗?如果是,为什么启用严格模式时 MySQL 不报错?

【问题讨论】:

  • 根据我的经验,Mysql 更喜欢做错事,尽可能不返回错误。我想知道其他数据库是否也会出现同样的问题
  • 我认为您可以通过表达式 (5102 * POWER(2,47) 到浮点类型进行隐式数据类型转换,并在进行强制转换之前在加法中失去精度。看看SELECT CAST(5102 * POWER(2, 47) AS UNSIGNED), 5102 * POWER(2, 47);
  • 并且没有溢出,因为没有定义数据类型的列。
  • 在此处查看我的答案:stackoverflow.com/questions/24442089/… 用于 Javascript,但我怀疑此处涉及类似问题。
  • @Barmar 有趣的是,不同的机器得到不同的结果。在带有 MySQL 5.6.6 的 sqlfiddle 上(正如它所说),演员表根本没有任何区别,在我的带有 MySQL 5.6.16 的 Windows 8.1 64 位计算机上(根本没有太大区别)我可以重现问题。

标签: mysql sql


【解决方案1】:

有些操作在DECIMAL 中完成,有些在DOUBLE 中完成。这应该可以解释为什么在第 16 位有效数字之后数字会有所不同。

这是另一种方法:

5002622390 + (5102 << 47)

&lt;&lt;是二进制移位,所以和*POW(2, ...)效果一样

使用 DECIMAL 得到正确答案 718042670591505846:

SELECT CAST(5002622390 AS DECIMAL) + (5102 * 140737488355328);
SELECT CAST(5002622390 AS DECIMAL) + (5102 << 47)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-25
    • 2020-12-07
    • 2011-02-28
    相关资源
    最近更新 更多