【发布时间】:2015-11-10 15:10:40
【问题描述】:
我对这个选择有疑问:
select @a := 992.7500, ROUND(@a * (1 + 18 / 100), 2) AS Total;
作为 Total 它得到 1171.44,但它的值必须是 1171.45。如果执行 Workbench 并且我再次运行相同的选择,它会得到正确的值。
¿我怎样才能获得正确的价值?谢谢。
【问题讨论】:
我对这个选择有疑问:
select @a := 992.7500, ROUND(@a * (1 + 18 / 100), 2) AS Total;
作为 Total 它得到 1171.44,但它的值必须是 1171.45。如果执行 Workbench 并且我再次运行相同的选择,它会得到正确的值。
¿我怎样才能获得正确的价值?谢谢。
【问题讨论】:
那是正确的值。它只是根据spec 使用银行家的四舍五入。
ROUND() 根据第一个参数的类型使用以下规则:
对于精确值数字,ROUND() 使用“距离零的一半” 或“向最近舍入”规则:小数部分为 0.5 的值 如果为正数或更大,则向上舍入到下一个整数或向下舍入到 如果为负,则为下一个整数。 (换句话说,它从 零。)小数部分小于 0.5 的值向下舍入为 如果为正则为下一个整数,如果为负则为下一个整数。
对于近似值数字,结果取决于 C 库。在 许多系统,这意味着 ROUND() 使用“四舍五入到最接近的偶数” 规则:具有任何小数部分的值四舍五入到最接近的偶数 整数。
银行家四舍五入或“四舍五入到最接近的偶数”是不精确数值(如 double)的首选舍入方法,因为它解决了备选方案的向上偏差。
Bankers Rounding 是一种将数量四舍五入为整数的算法, 其中与两个最接近的整数等距的数字 四舍五入到最接近的偶数。因此,0.5 向下舍入为 0; 1.5 舍入到 2。
【讨论】:
如果您使用SET 语句,您可以在第一次运行时获得正确的值。
SET @a = 992.7500;
select ROUND(@a * (1 + 18 / 100), 2) AS Total;
https://dev.mysql.com/doc/refman/5.6/en/user-variables.html
作为一般规则,除了在 SET 语句中,您不应该为用户变量赋值并在同一语句中读取值。
为变量赋值并在同一非 SET 语句中读取值的另一个问题是,变量的默认结果类型基于语句开头的类型。
@a 是使用 SET 时的精确值数字。在SELECT 语句中分配的@a 似乎不是精确值而是近似值。
MySQL 8.0(当前)仍然支持您编写的语法,但该语法可能会在 MySQL 的未来版本中被删除。
以前的 MySQL 版本可以在 SET 以外的语句中为用户变量赋值。 MySQL 8.0 支持此功能以实现向后兼容性,但可能会在 MySQL 的未来版本中删除。
【讨论】: