What does normalization actually buy you?
Normalization is a set of rules about where each fact lives. The goal is that every fact is stored in exactly one place, so that changing it means changing it once. The payoff is not tidiness; it is that the data cannot drift out of sync with itself.
-- Unnormalised: the customer city is repeated on every order row.
CREATE TABLE orders_flat (
id INTEGER PRIMARY KEY,
customer_name VARCHAR(120) NOT NULL,
customer_city VARCHAR(80) NOT NULL,
amount DECIMAL(10, 2) NOT NULL
);
INSERT INTO orders_flat (id, customer_name, customer_city, amount) VALUES
(1, 'Ada Lovelace', 'London', 120.00),
(2, 'Ada Lovelace', 'London', 340.50),
(3, 'Grace Hopper', 'New York', 75.25);
-- Ada moves to Cambridge. Only one copy gets updated.
UPDATE orders_flat SET customer_city = 'Cambridge' WHERE customer_name = 'Ada Lovelace';
SELECT id, customer_name, customer_city FROM orders_flat ORDER BY id;Three rows come back, and the data is now wrong: order 1 says Cambridge while order 2 still says London, and both belong to the same person. The city is stored in two places and the two copies disagree. This is an update anomaly, and it is not a hypothetical — a duplicated value that is updated through one path but not the other is one of the most common data-quality bugs there is.
There are two more anomalies that the same duplication causes. An insertion anomaly: you cannot record a new customer without creating an order for them, because there is nowhere to put the customer's details on their own. And a deletion anomaly: if a customer has exactly one order and you delete that order, you lose the customer's name and city entirely, because their only copy was in the row you removed.
Normalization removes all three by separating the facts into their own tables, so that the customer table holds the name and city once and the orders table holds the amounts, joined by an id. The cost is joins: to show a customer's city next to their orders you now need a join on every query, and a report that flattens it back is doing the same work the duplicated column was saving.