The Starting Point: An Unnormalized Table

Imagine a single table tracking orders:

OrderIDCustomerNameCustomerCityProducts
1Riya ShahMumbaiLaptop, Mouse
2Riya ShahMumbaiKeyboard

Two problems already: the Products column stores multiple values in one cell, and the customer's city is repeated in every order row.

First Normal Form (1NF) — Atomic Values

Rule: every column must hold a single, atomic value — no comma-separated lists, no repeating groups.

OrderIDCustomerNameCustomerCityProduct
1Riya ShahMumbaiLaptop
1Riya ShahMumbaiMouse
2Riya ShahMumbaiKeyboard

Splitting the product list into one row per product makes the table 1NF-compliant — but now customer data is duplicated even more.

Second Normal Form (2NF) — No Partial Dependency

Rule: applies to tables with a composite primary key (here, OrderID + Product). Every non-key column must depend on the whole key, not just part of it. CustomerName and CustomerCity only depend on OrderID, not on Product — that's a partial dependency, so we split it out.

Orders
OrderIDCustomerNameCustomerCity
1Riya ShahMumbai
2Riya ShahMumbai
OrderItems
OrderIDProduct
1Laptop
1Mouse
2Keyboard

Third Normal Form (3NF) — No Transitive Dependency

Rule: non-key columns must depend only on the primary key, not on other non-key columns. In the Orders table, CustomerCity depends on CustomerName, not directly on OrderID — that's a transitive dependency. Fix it by pulling customers into their own table:

Customers
CustomerIDCustomerNameCity
101Riya ShahMumbai
Orders
OrderIDCustomerID
1101
2101

Now if Riya moves to Pune, you update one row in Customers — not every order she's ever placed.

The Three Anomalies Normalization Prevents

AnomalyExample Without Normalization
InsertionCan't add a new customer until they place an order, because customer data only exists inside order rows
UpdateCustomer's city is stored in 50 order rows — update 49 of them and the data is now inconsistent
DeletionDeleting a customer's only order accidentally deletes the only record of their city

⚠️ Normalization Has a Cost: More JOINs

Every normal form you add usually means splitting one table into more tables, which means more JOINs to reconstruct the full picture. For read-heavy systems (dashboards, reports, analytics), this can hurt performance — which is why denormalization is a deliberate, common trade-off in those contexts.

Normalization vs Denormalization

AspectNormalizedDenormalized
RedundancyMinimalIntentional duplication
WritesUpdate one placeMust update every duplicate
ReadsNeed JOINsOften a single table lookup
Best forOLTP — orders, payments, inventoryOLAP — dashboards, reporting, read-heavy APIs

💡 In Practice

Most production schemas aim for 3NF as a default, then deliberately denormalize specific tables once a real performance bottleneck is measured — not before. Normalize first for correctness, denormalize later for speed where it's proven necessary.

How We Research and Update This Guide

We test the underlying formula or workflow, compare outputs with reliable references, and revise examples whenever the page content changes.

  • The workflow or formula is tested directly in the tool and compared against independent reference examples.
  • Examples are kept practical so readers can verify the result without hidden assumptions.
  • Pages are revised whenever the interface, calculation flow, or surrounding guidance materially changes.

Frequently Asked Questions — Database Normalization