SQL Normalization
Normalization separates facts so a change has one clear place to happen. Storing a customer's current city on every order would repeat the same fact and invite inconsistent updates. Relationships let a query bring the pieces together when needed.
Understand the idea
The shop separates customers, products, orders, and order items. Order items record the quantity and historical unit price for a purchase. That price is a fact about the purchase, so keeping it is deliberate rather than redundant copying of the current product price. Design around dependencies and required history, not a slogan that all repeated values are wrong.
Where to try it
Run this example in the SQL playground. The lesson link loads the shop tables and sample rows before this query. Select Run when you are ready. Every run starts fresh, so your changes do not affect the website or a previous run.
SQLite sample data · MySQL / MariaDB sample data · See the sample tables
A worked example
SELECT o.order_id, c.name, p.name AS product, i.unit_price_cents
FROM orders AS o
JOIN customers AS c ON c.customer_id = o.customer_id
JOIN order_items AS i ON i.order_id = o.order_id
JOIN products AS p ON p.product_id = i.product_id
WHERE o.order_id = 101
ORDER BY i.product_id;
Read the result
The receipt combines separate tables and shows two lines for order 101. Customer identity and current product names are read through relationships, while the line price records the sale.
Try one change
List which facts in a real invoice must remain unchanged after a customer edits an address or a product is renamed.