首页 > 解决方案 > MySQL舍入怪异

问题描述

我正在开发一个发票模块,当我计算四舍五入的金额时遇到了一些奇怪的问题,我无法绕开我的脑袋。

在 mysql shell 中执行此查询时,我得到不同的结果:

SELECT @amount := 1.005 AS decimalAmount, @rounded := ROUND(@amount) AS rounded, @diff := ROUND(@rounded - @amount, 2) AS roundOff, ROUND(@diff * 1e2) centsRounded;

我第三次运行查询它显示了我正在寻找的结果,但第一次和第二次不是出于某种原因。

+---------------+---------+----------+--------------+
| decimalAmount | rounded | roundOff | centsRounded |
+---------------+---------+----------+--------------+
|         1.005 |       1 |    -0.00 |           -0 |
+---------------+---------+----------+--------------+
1 row in set (0.000 sec)

+---------------+---------+----------+--------------+
| decimalAmount | rounded | roundOff | centsRounded |
+---------------+---------+----------+--------------+
|         1.005 |       1 |    -0.00 |           -0 |
+---------------+---------+----------+--------------+
1 row in set (0.000 sec)

+---------------+---------+----------+--------------+
| decimalAmount | rounded | roundOff | centsRounded |
+---------------+---------+----------+--------------+
|         1.005 |       1 |    -0.01 |           -1 |
+---------------+---------+----------+--------------+
1 row in set (0.000 sec)

有人可以解释为什么会这样吗?

标签: mysql

解决方案


有人可以解释为什么会这样吗?

说明书解释_

涉及用户变量的表达式的求值顺序未定义。例如,不能保证 SELECT @a, @a:=@a+1 先计算 @a 然后再执行赋值。

很确定您的查询中的评估是错误的。

如果您真的不需要 MySQL 用户变量,则很难避免使用它们。

我更想重写这个查询。

SELECT
    @amount := 1.005 AS decimalAmount
  , @rounded := ROUND(@amount) AS rounded
  , @diff := ROUND(@rounded - @amount, 2) AS roundOff
  , ROUND(@diff * 1e2) centsRounded;

或多或少像(有更多的重写选项)以避免使用 MySQL 的用户变量。

SELECT 
   record.amount
 , ROUND(record.amount) AS rounded
 , ROUND(ROUND(record.amount) - record.amount, 2) AS roundOff
 , ROUND(ROUND(record.amount) - record.amount, 2) * 1e2  AS centsRounded
FROM (
  SELECT 
   1.005 AS amount
) AS record

结果

| amount | rounded | roundOff | centsRounded |
| ------ | ------- | -------- | ------------ |
| 1.005  | 1       | -0.01    | -1           |

演示


推荐阅读