Data · Junior

Normalization: 1NF, 2NF and 3NF without memorizing

Normalization has a reputation as a boring subject full of memorization — 1NF, 2NF, 3NF, forms nobody remembers on the spot. But the idea behind it is simple and practical: organize data so that each fact is stored in a single place. Once you understand the problem each form solves, you don't need to memorize anything.

The problem: duplicated data causes anomalies

Imagine a single table recording orders with the customer's name and phone repeated on every row. Three things go wrong:

  • Update anomaly — the customer changes phone number and you have to change dozens of rows; miss one and the data becomes inconsistent.
  • Insertion anomaly — you can't register a new customer unless they've placed an order.
  • Deletion anomaly — deleting a customer's last order deletes the customer along with it.

To normalize is to eliminate these redundancies by splitting the table into smaller, well-defined ones.

1NF: atomic values

The First Normal Form requires each cell to hold a single value. No telefones column with "1199, 1188" separated by commas, and no repeated columns like produto1, produto2. If you have a list inside a cell, it becomes rows in its own table.

2NF: dependence on the whole key

The Second Normal Form only matters when the primary key is composite (two or more columns). It says: every non-key attribute must depend on the whole key, not on part of it.

In an order-items table with key (pedido_id, produto_id), nome_produto depends only on produto_id — part of the key. That violates 2NF. The fix is to move the name to a products table.

3NF: no transitive dependency

The Third Normal Form tackles transitive dependency: a non-key attribute that depends on another non-key attribute. If in the customers table you store cidade (city) and estado (state), and the state is determined by the city, there's a transitive dependency. City becomes its own table.

An evolving example

See how a messy table gets transformed:

Before (everything together)After (3NF)
pedidos: id, cliente_nome, cliente_tel, produtos (list), produto_precoclientes: id, nome, tel
Customer and product data repeated on every rowprodutos: id, nome, preco
Anomalies on every updateitens_pedido: pedido_id, produto_id, qtd

Each fact — the customer's phone, the product's price — now lives in exactly one place.

Don't memorize "2NF is partial dependency". Ask: "is this data repeated for no reason? If I change it, will I have to change it in several places?" If so, it still needs normalizing.

When to denormalize on purpose

Normalization is great for writes and integrity, but it can be costly on reads: to build a report, you join many tables with JOINs. In read-heavy scenarios, it's sometimes worth denormalizing on purpose — duplicating data in a controlled way to avoid joins and gain speed. It's a conscious trade-off decision, not laziness. Analytical models, as we'll see in dimensional modeling, embrace this idea.

Conclusion

The first three normal forms solve, one by one, specific sources of redundancy: non-atomic values, partial dependency and transitive dependency. Understand the problem behind each one and you normalize by reasoning. In interviews it's common to be asked which form a table violates — and day to day, knowing when to keep the schema normalized and when to relax it on purpose is what distinguishes a good data design.

Read also

Back to the track