MySQL FLOAT(10,2) – Precision Problems with Money

MySQL

I have a table like this:

mysql> describe transactions;
+-----------------------+---------------+------+-----+---------+----------------+
| Field                 | Type          | Null | Key | Default | Extra          |
+-----------------------+---------------+------+-----+---------+----------------+
| id                    | int(11)       | NO   | PRI | NULL    | auto_increment |
| cost                  | float(10,2)   | YES  |     | NULL    |                |
+-----------------------+---------------+------+-----+---------+----------------+

I (naively?) thought that would be a good way to store amounts.
I am 3 days from release, and I discovered this:

mysql> UPDATE transactions SET cost = 162295.99 WHERE id = 14891;
Query OK, 0 rows affected (0.01 sec)
Rows matched: 1  Changed: 0  Warnings: 0

mysql> select * from transactions where id = 14891;
+-------+---------------+
| id    | cost          |

+-------+---------------+
| 14891 |     162295.98 | 
+-------+---------------+

…?!? I entered .99, not .98!
So:

  • Why is this doing it?
  • How do I get out of this problem?
  • Would decimal work? I tried with:

    mysql> alter table transactions modify cost decimal(12,2) NULL DEFAULT NULL;
    Query OK, 1120 rows affected, 119 warnings (0.14 sec)
    Records: 1120 Duplicates: 0 Warnings: 119

    mysql>

However I am getting scary warnings. With "show warnings" I get:

mysql> show warnings;
+-------+------+---------------------------------------------+
| Level | Code | Message                                     |
+-------+------+---------------------------------------------+
| Note  | 1265 | Data truncated for column 'cost' at row 10  |
| Note  | 1265 | Data truncated for column 'cost' at row 369 |
| Note  | 1265 | Data truncated for column 'cost' at row 371 |
| Note  | 1265 | Data truncated for column 'cost' at row 378 |
| Note  | 1265 | Data truncated for column 'cost' at row 402 |
| Note  | 1265 | Data truncated for column 'cost' at row 403 |
+-------+------+---------------------------------------------
  • How do I see which one "row 10" is anyway?

  • KEY QUESTION: How do I get out of this hole safely?

  • (Rhetorical question bonus question) Why didn't this happen like 3 months ago, when fixing would have been easy?

Best Answer

Known problem with IEEE floats. Use DECIMAL

To fix

  • add new column of correct data type
  • copy data over (check for conversion errors here)
  • drop bad column
  • rename new column to correct name

Why? Murphy's Law.