150 lines
3.9 KiB
Markdown
150 lines
3.9 KiB
Markdown
---
|
||
title: FLOAT Made My Dollars Float Away - FLOAT vs DECIMAL in MySQL 💸
|
||
date: 19th Sep 2025
|
||
description: Recently I got a task Alter a table column from `FLOAT` to `DECIMAL(10,2)
|
||
image: /blogs-img/blog8.png
|
||
alt: FLOAT Made My Dollars Float Away - FLOAT vs DECIMAL in MySQL 💸
|
||
ogImage: /blogs-img/blog8.png
|
||
tags: ["mysql", "float", "decimal"]
|
||
published: true
|
||
---
|
||
|
||
### FLOAT Made My Dollars Float Away - FLOAT vs DECIMAL in MySQL
|
||
|
||
Recently I got a task:
|
||
|
||
> **"Alter a table column from `FLOAT` to `DECIMAL(10,2)`"**
|
||
|
||
I thought:
|
||
_"Pff, easy task. Just run an `ALTER TABLE` and done. Why is this even a ticket?"_
|
||
|
||
But then I read the description.
|
||
Turns out, **FLOAT was causing data loss**, and I needed to convert it without losing data.
|
||
|
||
That’s when I realized: this isn’t just about one query. It’s about how **FLOAT silently eats your money** in MySQL.
|
||
|
||
### Why FLOAT is a Problem
|
||
|
||
`FLOAT` in MySQL is a **binary floating-point type**.
|
||
It doesn’t store exact values — only approximations.
|
||
|
||
That’s fine for rocket science 🚀 or graphics rendering 🎮, but for **money** where every cent matters? Disaster.
|
||
|
||
Think of `FLOAT` as a leaky bucket. You pour in `$1,000,000.25`… and it gives you back `$999,999.94`.
|
||
|
||
Not funny when it’s your salary.
|
||
|
||
### Example of Data Loss
|
||
|
||
```sql
|
||
CREATE TABLE money_float (
|
||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||
amount FLOAT
|
||
);
|
||
|
||
INSERT INTO money_float (amount) VALUES (1000000.25), (123456789.99);
|
||
|
||
SELECT * FROM money_float;
|
||
```
|
||
|
||
Result:
|
||
|
||
| id | amount |
|
||
| --- | ------------ |
|
||
| 1 | 1000000.25 |
|
||
| 2 | 123456792.00 |
|
||
|
||
We inserted `123456789.99`, but got back `123456792.00`.
|
||
The bigger the number, the worse the corruption.
|
||
|
||
### But Why Does FLOAT Lose Data?
|
||
|
||
Here’s the fun part. Let’s make it simple.
|
||
|
||
- `FLOAT` stores numbers in **binary (base 2)**.
|
||
- But not every decimal number can be written exactly in binary.
|
||
|
||
Example:
|
||
|
||
- In decimal, `0.1` is simple.
|
||
- In binary, `0.1` is **infinite repeating**: `0.0001100110011…`
|
||
- So `FLOAT` cuts it off at some point and stores an approximation.
|
||
|
||
That’s why when you do:
|
||
|
||
```sql
|
||
INSERT INTO money_float (amount) VALUES (0.1);
|
||
SELECT amount FROM money_float;
|
||
```
|
||
|
||
You might see something like `0.10000000149`.
|
||
|
||
Now imagine this tiny error repeated in **millions of dollars**.
|
||
Errors pile up, and suddenly your 9-digit amount looks… off.
|
||
|
||
### DECIMAL to the Rescue
|
||
|
||
`DECIMAL` stores numbers differently:
|
||
|
||
- Instead of binary approximation, it stores **exact digits as strings** internally.
|
||
- That means `123456789.99` is stored as exactly `123456789.99`.
|
||
|
||
```sql
|
||
CREATE TABLE money_decimal (
|
||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||
amount DECIMAL(15,2)
|
||
);
|
||
|
||
INSERT INTO money_decimal (amount) VALUES (1000000.25), (123456789.99);
|
||
|
||
SELECT * FROM money_decimal;
|
||
```
|
||
|
||
Result:
|
||
|
||
| id | amount |
|
||
| --- | ------------ |
|
||
| 1 | 1000000.25 |
|
||
| 2 | 123456789.99 |
|
||
|
||
Perfect. ✅ No rounding surprises.
|
||
|
||
### Why ALTER Won’t Save You
|
||
|
||
Here’s the trap I fell into:
|
||
|
||
```sql
|
||
ALTER TABLE money_float MODIFY amount DECIMAL(15,2);
|
||
```
|
||
|
||
You’d think this fixes it, right?
|
||
Nope. ❌
|
||
|
||
The data was already corrupted when it was first inserted as `FLOAT`.
|
||
`ALTER` just moves the already-broken value into `DECIMAL`.
|
||
|
||
Garbage in → garbage out.
|
||
|
||
### Visual: FLOAT vs DECIMAL
|
||
|
||
```
|
||
FLOAT (approximation in binary):
|
||
123456789.99 ---> 123456792.00 💀
|
||
|
||
DECIMAL (exact digits):
|
||
123456789.99 ---> 123456789.99 ✅
|
||
```
|
||
|
||
### Lessons Learned
|
||
|
||
- Never use `FLOAT`/`DOUBLE` for money.
|
||
- Always use `DECIMAL(precision, scale)` (e.g., `DECIMAL(15,2)`).
|
||
- If your table already has money in `FLOAT`, you cannot fix the lost precision with `ALTER`. You’ll need to re-import or clean it at the source.
|
||
|
||
### Final Thought
|
||
|
||
Using `FLOAT` for money is like paying your salary in **Monopoly money**. 🎲💵
|
||
It looks okay until you try to spend it — then you realize it’s worthless.
|
||
|
||
Stick with `DECIMAL`, and your dollars will stay safe. ✅
|