MySQL的计算精度

时间:2018-10-03 09:16:19

标签: mysql

我有这个奇怪的问题。我有一个包含2个数字的表,但是简单的计算会导致精度错误:

mysql> create table tblX as select '2.7' as H, '2100' as H2;
Query OK, 1 row affected (0.32 sec)
Records: 1  Duplicates: 0  Warnings: 0

mysql> select *, h-h2/1000 from tblX; 
+-----+------+--------------------+
| H   | H2   | h-h2/1000          |
+-----+------+--------------------+
| 2.7 | 2100 | 0.6000000000000001 |
+-----+------+--------------------+
1 row in set (0.00 sec)

此示例重现了我在设置中遇到的问题,其中以某些字段必须为varchars的方式提取公式,字段及其值的方式,而其他字段则用于上述计算。因此公式无法更改。另一个示例可能是一个公式,例如:if(code='c' and h-h2/1000>0.6,h,0) 字段是通过透视操作创建的。

我的假设是,将varchar隐式转换为十进制会导致此问题。我的问题是:是否有任何服务器设置可以更改此隐式转换。还是对此有其他解决方案。

编辑: 如果我这样修改列:

alter table tblX MODIFY column h decimal(20,4), MODIFY h2 decimal(20,4);

结果将是正确的。但是我不知道这些列的名称,因为它们是在临时表中动态创建的。如果可以创建一个脚本来修改仅包含数字值的所有列,那就太好了。

2 个答案:

答案 0 :(得分:0)

我不知道任何服务器设置。但是您也可以在sql中进行显式转换。 尝试这样的事情:

select *, CAST(h-h2/1000 AS DECIMAL(10,2)) from tblX; 

请参阅MySQL文档。 https://dev.mysql.com/doc/refman/5.5/en/fixed-point-types.html

答案 1 :(得分:0)

问题是,公式中的varchar显然隐式转换为浮点数而不是小数。在这种情况下,不能更改公式。但是修改列数据类型是一种选择。

解决方案是创建一个存储过程,该存储过程循环遍历相关列并将其修改为十进制数据类型。

包含错误数据类型的表称为tmp。

我制作了一个名为tmpPar的临时表,其中包含所有参与公式的列名称作为数值。然后,我设置一个游标并遍历所有这些列。光标循环如下所示:

DECLARE a varchar(255);
DECLARE cur1 CURSOR FOR SELECT CName FROM tmpPar;    
...
Open cur1;
    simple_loop: LOOP
        fetch cur1 into a;
        IF no_more_rows=1 THEN
          LEAVE simple_loop;
        END IF;
        set @sql = null;
        set @sql = concat('alter table tmp MODIFY column ' , a , ' decimal(20,4)');
        PREPARE stmt FROM @sql;
        EXECUTE stmt;
    END LOOP simple_loop;
    Close cur1;