# Normalization in Plain English: 1NF, 2NF, 3NF

> What each normal form removes, why OLTP schemas are normalized, and why analytical models deliberately denormalize.

- Source: https://akshaythakare.com/notes/data-modeling/normalization-basics
- Topic: Data Modeling
- Level: beginner
- Reading time: 2 min
- Tags: data-modeling, normalization, fundamentals, interview
- Updated: 2026-10-11

## 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:

```text
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:

```text
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.

> **Tip: Interview framing**
>
> "OLTP normalizes so writes stay consistent; the warehouse denormalizes into star schemas so reads stay simple."
