Add new blog post: FLOAT Made My Dollars Float Away - FLOAT vs DECIMAL in MySQL (#91)
This commit is contained in:
committed by
GitHub
parent
13da7d4a79
commit
6a2ed6dee5
149
content/blogs/8. float-make-my-dollar-float-away.md
Normal file
149
content/blogs/8. float-make-my-dollar-float-away.md
Normal file
@@ -0,0 +1,149 @@
|
||||
---
|
||||
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. ✅
|
||||
Reference in New Issue
Block a user