MySQL 从 float (10,2) 到 fixed(10,2) 的转换

Bry*_*gee 4 mysql floating-point

我有一个数据库,其中包含存储为浮点数的财务数据。自然地,这可能会在随机时间出现真正的问题(例如,当存在无法使用浮点算法足够接近地近似的精确值时)。

我的问题是

  • ALTER TABLE table MODIFY field fixed(10,2)选择字段时使用会 保留 MySQL 当前显示的固定值吗?
  • 有没有可能价值不是这个?

Rol*_*DBA 7

坏消息:我认为价值不会被保留!!!

我写了这篇文章(2011 年 7 月 25 日),展示了浮点数对转换的敏感程度。

好消息:以下是您可以安全地比较数据转换的方法:

如果你的桌子有这些特点

  • 表被称为 moneytable
  • 您希望转换的字段被称为 moneyfield
  • 主键被称为 moneyid

然后运行这些命令:

DROP TABLE IF EXISTS moneytabletest;
CREATE TABLE moneytabletest LIKE moneytable;
ALTER TABLE moneytabletest MODIFY moneyfield fixed(10,2);
INSERT INTO moneytabletest SELECT * FROM moneytable;
SELECT A.moneyid,A.moneyfield olddata,B.moneyfield newdata
FROM moneytable A LEFT JOIN moneytabletest B USING (moneyid)
WHERE A.moneyfield <> B.moneyfield;
Run Code Online (Sandbox Code Playgroud)

这是底线: 如果有任何行LEFT JOIN查询中返回,则转换将是错误的。您将不得不修改 的定义moneyfield,重新加载moneytabletest表,并LEFT JOIN一次又一次地运行查询,直到没有行从LEFT JOIN查询中返回。一旦零(0) 行回来,你就会知道什么转换是安全的。

试一试 !!!


Bry*_*gee 5

根据Rolando的回答,我想出了一个更简单的方法来进行分阶段转换,然后进行比较。在相关表中,我首先添加了相同类型的新字段。我镜像了这些值,运行了转换,并比较了结果值。例如,Amount float(10,2) NOT NULL我用过:

ALTER TABLE `table` ADD `AmountStaged` float(10,2) NOT NULL;
UPDATE `table` SET `AmountStaged` = `Amount`;
ALTER TABLE `table` MODIFY `AmountStaged` decimal(10,2) NOT NULL;
SELECT * FROM `table` WHERE round(`Amount`,2) <> `AmountStaged`;
Run Code Online (Sandbox Code Playgroud)

令人惊讶的是,对于多个表(有些表的行数超过 30k),只有一个值不匹配。幸运的是,已删除的标志是在该特定记录上设置的,因此无论如何它都是无关紧要的。因此,在获得有利结果后,最后一步是两个命令:

ALTER TABLE `table` DROP `Amount`;
ALTER TABLE `table` CHANGE `AmountStaged` `Amount` decimal(10,2) NOT NULL;
Run Code Online (Sandbox Code Playgroud)

编辑:零停机替代方案是删除AmountStaged列并转换Amount列,因为转换应该与我们运行测试的转换相同。

ALTER TABLE `table` MODIFY `Amount` decimal(10,2) NOT NULL;
ALTER TABLE `table` DROP `AmountStaged`;
Run Code Online (Sandbox Code Playgroud)