Normalization in Plain English: 1NF, 2NF, 3NF
What each normal form removes, why OLTP schemas are normalized, and why analytical models deliberately denormalize.
Data ModelingBeginner2 min readUpdated 11 Oct 2026
The goal
Normalization stores each fact once, so an update happens in one place and the data cannot contradict itself.
Start with a messy table
| order_id | customer | customer_city | products |
|---|---|---|---|
| O1 | Asha | Pune | Rice, Milk |
1NF — one value per cell
Split repeating values into rows:
| order_id | customer | customer_city | product |
|---|---|---|---|
| O1 | Asha | Pune | Rice |
| O1 | Asha | Pune | Milk |
2NF — every column depends on the whole key
With key (order_id, product), customer depends only on order_id. Move it out:
orders(order_id, customer)
order_lines(order_id, product)3NF — no column depends on another non-key column
customer_city depends on the customer, not on the order:
customers(customer_id, name, city)
orders(order_id, customer_id)
order_lines(order_id, line_no, product_id, qty)Now a customer moving city changes one row.
Why warehouses denormalize again
Analytical queries would need many joins on a 3NF schema. A star schema flattens descriptive attributes into wide dimensions (city, region and country all in dim_customer). That trades some redundancy for simple, fast queries.
Finished this note?
