Files
Cloud-Blog/content/blogs/8. float-make-my-dollar-float-away.md
2025-12-20 18:46:45 +08:00

150 lines
3.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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.
Thats when I realized: this isnt just about one query. Its about how **FLOAT silently eats your money** in MySQL.
### Why FLOAT is a Problem
`FLOAT` in MySQL is a **binary floating-point type**.
It doesnt store exact values — only approximations.
Thats 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 its 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?
Heres the fun part. Lets 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.
Thats 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 Wont Save You
Heres the trap I fell into:
```sql
ALTER TABLE money_float MODIFY amount DECIMAL(15,2);
```
Youd 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`. Youll 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 its worthless.
Stick with `DECIMAL`, and your dollars will stay safe. ✅