DECIMAL NUMERIC 数据类型中的 MySQL 精度问题
Posted
技术标签:
【中文标题】DECIMAL NUMERIC 数据类型中的 MySQL 精度问题【英文标题】:MySQL Precison Issues in DECIMAL NUMERIC data type 【发布时间】:2013-08-31 16:27:08 【问题描述】:在为科学应用编写函数时,我遇到了问题。我将其追溯到 mysql 缺乏精确性。
这是官方文档中声称 DECIMAL 的最大位数为 65 - http://dev.mysql.com/doc/refman/5.6/en/fixed-point-types.html 的页面。它还描述了如果值超过指定的精度,将如何四舍五入。
这里是可重现的代码(一个mysql存储函数)来测试它-
DELIMITER $$
DROP FUNCTION IF EXISTS test$$
CREATE FUNCTION test
(xx DECIMAL(30,25)
)
RETURNS DECIMAL(30,25)
DETERMINISTIC
BEGIN
DECLARE result DECIMAL(30,25);
SET result = 0.339946499848118887e-4;
RETURN(result);
END$$
DELIMITER ;
如果你将上面的代码保存在一个名为test.sql的文件中,你可以通过在mysql提示符下执行以下命令来运行它——
source test.sql;
select test(0);
它产生输出 -
+-----------------------------+
| test(0) |
+-----------------------------+
| 0.0000339946499848118900000 |
+-----------------------------+
1 row in set (0.00 sec)
如您所见,该数字在第 20 位四舍五入,然后添加五个零以达到所需/指定的精度。那是作弊。
是我弄错了,还是文档有误?
【问题讨论】:
+1 。 . .我已经验证即使cast(0.0000339946499848118887' as decimal(60, 25))
也是如此。我认为问题可能出在浮点常量上,但字符串到十进制的转换也会发生。
更新:我发现,在声明 DECIMAL(M, D) 时,MySQL 在 D>30 时返回错误。我找不到它的官方文档,但我想 30 是 D 的极限。但上面的发现也与此相矛盾。
@GordonLinoff:我对 SQL 了解不多,但是在 mysql shell 中,语句 select cast('0.0000339946499848118887' as decimal(60, 25));
按预期返回 0.0000339946499848118887000
。你看到了什么?
【参考方案1】:
这是因为 mysql 将0.339946499848118887e-4
视为float
并将0.0000339946499848118887
视为fixed point
。
mysql> select cast( 0.339946499848118887e-4 as DECIMAL(30, 25));
+----------------------------------------------------+
| cast( 0.339946499848118887e-4 as DECIMAL(30, 25)) |
+----------------------------------------------------+
| 0.0000339946499848118900000 |
+----------------------------------------------------+
1 row in set (0.00 sec)
mysql> select cast( 0.0000339946499848118887 as DECIMAL(30, 25));
+-----------------------------------------------------+
| cast( 0.0000339946499848118887 as DECIMAL(30, 25)) |
+-----------------------------------------------------+
| 0.0000339946499848118887000 |
+-----------------------------------------------------+
1 row in set (0.00 sec)
如precision math - expression handling 上的 mysql 文档中所述 -
如果存在任何近似值,则表达式为近似值,并使用浮点运算进行评估。
引用自 numerical types 上的文档,
两个看起来相似的数字可能会被区别对待。例如,2.34 是一个精确值(定点)数,而 2.34E0 是一个近似值(浮点)数。
【讨论】:
我认为这两个答案都可能是正确的答案。必须掷硬币来选择其中一个!有启发性的答案,谢谢。【参考方案2】:我对 SQL 一无所知,但我的猜测是这一行:
SET result = 0.339946499848118887e-4;
如果 MySQL 与我知道的其他语言类似,那么这将首先评估右侧,然后然后将值分配给 result
。无论result
被声明为何种类型或声明具有何种精度,右侧在评估时是否已经失去精度都没关系。这几乎肯定是这里发生的事情。
我可以重现你的结果,但是如果我把那行改成
SET result = cast('0.339946499848118887e-4' as decimal(30, 25));
(从字符串而不是未指定精度的浮点常量进行转换)然后我正确地得到了
+-----------------------------+
| test(0) |
+-----------------------------+
| 0.0000339946499848118887000 |
+-----------------------------+
1 row in set (0.00 sec)
根据需要。所以这就是你的解决方法。
顺便说一句,DECIMAL(precision, scale)
中的scale
不能大于 30 的文档似乎在 12.19.2. DECIMAL Data Type Changes 部分:
DECIMAL 列的声明语法是 DECIMAL(M,D)。这 MySQL 5.6 中参数的取值范围如下:
M 是最大位数(精度)。它的范围为 1 到 65。(旧版本的 MySQL 允许的范围是 1 到 254。)
D 是小数点右边的位数( 规模)。取值范围为 0 到 30,且不得大于 M。
【讨论】:
哦,我猜我的 'cast' 和 'decimal' 也可能是大写的。但我不明白为什么在惯用的 SQL 中有这么多的叫喊声。 :-) Anshul 在下面的回答澄清了 MySQL 对数字的不同处理方式取决于它们的编写方式!以上是关于DECIMAL NUMERIC 数据类型中的 MySQL 精度问题的主要内容,如果未能解决你的问题,请参考以下文章
sql中数据类型decimal(1, 1)和numeric (1, 1)之间的差异[重复]