Home Databases

A Beginner's Guide to Database Normalisation for Small Business Apps

Databases

October 09, 2026

A Beginner's Guide to Database Normalisation for Small Business Apps

Most small business apps start with one table and good intentions. A spreadsheet of customers, a list of orders, maybe an invoice or two. Then the app grows, someone adds a "product name" column to the orders table, and suddenly the same customer address appears in forty-seven rows — three of them with a different postcode. Normalisation is the discipline that stops this happening. It is not academic box-ticking; it is the difference between a database you can trust and one you spend every Friday afternoon cleaning up by hand.

This guide walks through the first three normal forms, the ones that cover the vast majority of small business data. We will use a single running example: a small app for a bike repair shop, with customers, jobs and parts.

What Normalisation Actually Means

Normalisation is the process of organising tables so that each fact is stored in exactly one place. That is it. Everything else — the numbered forms, the rules about dependencies — exists to help you achieve that goal consistently.

The benefits are practical rather than theoretical. When a customer changes their phone number, you update one row instead of hunting through a table. When two rows disagree, that is a bug waiting to happen, and normalised schemas make disagreement impossible by design.

The trade-off is real too: more tables mean more joins, and joins mean slightly more complex queries. For a small business app, that cost is almost always worth paying. You are optimising for correctness and maintainability, not for squeezing the last millisecond out of a report.

First Normal Form: One Value Per Cell

A table is in first normal form (1NF) when every column holds a single, atomic value and every row is unique.

Here is a jobs table that breaks the rule:

  • job_id: 1042
  • customer: Priya Shah
  • parts_used: brake pads, chain, inner tube
  • mechanic: Tom

The parts_used column is the problem. You cannot easily count how many chains the shop used last month, and you cannot remove a single part from the list without rewriting the whole string. The fix is to give parts their own table, with one row per part per job.

Two habits will keep you in 1NF without much thought. First, never store comma-separated lists in a column; if you are tempted, you probably need a related table. Second, give every table a primary key — a unique identifier such as job_id — so each row can be referenced unambiguously.

Second Normal Form: Every Column Depends on the Whole Key

Second normal form (2NF) only becomes relevant when a table has a composite primary key, meaning two or more columns together identify a row. The rule is simple: every non-key column must depend on the entire key, not just part of it.

Consider a jobs_parts table where the key is (job_id, part_id), and the columns include quantity and part_name. The quantity depends on both the job and the part, which is correct. But part_name depends only on part_id — it would be the same whether the part appears on one job or a hundred.

That makes it a partial dependency, and it belongs in the parts table instead. The jobs_parts table shrinks to three columns: job, part and quantity. If a supplier renames a brake pad, you change one row in one table.

A quick sanity check

Ask yourself: if I knew only part of the primary key, could I still work out this column's value? If yes, that column is in the wrong table.

Third Normal Form: No Indirect Dependencies

Third normal form (3NF) extends the idea. A table is in 3NF when it is in 2NF and no non-key column depends on another non-key column. In plain terms: nothing should be derivable from something else in the same table unless it is the key.

Say the jobs table looks like this:

  • job_id (primary key)
  • customer_id
  • customer_postcode
  • mechanic_id
  • mechanic_hourly_rate
  • job_date

Customer_postcode depends on customer_id, not on the job. The same goes for mechanic_hourly_rate and mechanic_id. Both belong in their own tables, leaving the jobs table to describe the job itself.

This is where normalisation pays off most visibly. If Tom gets a pay rise, you update one row in the mechanics table rather than every job he has ever worked on — and you avoid the situation where half his historical jobs show the old rate and half show the new one.

A Reasonable Stopping Point

Third normal form is where most small business schemas should live. Getting there is straightforward if you work through the forms in order:

  1. Split any column holding multiple values into separate rows or tables (1NF).
  2. Move columns that depend on only part of a composite key into their own table (2NF).
  3. Move columns that describe another non-key column into that column's table (3NF).

Beyond this, there are higher forms — Boyce-Codd, fourth, fifth — but they rarely change anything for an app with a handful of tables. Some deliberate denormalisation is also fine and often sensible: storing a calculated order total on the order row, for instance, saves recalculating it on every page load. The key word is deliberate. Know which rule you are breaking and why, and document it so the next developer does not "fix" it by accident.

Bringing It Back to Your App

You do not need to redraw your whole schema this afternoon. Pick your messiest table — usually the one with the most columns or the most repeated text — and check it against the three rules above. Move one thing at a time, keep your primary keys stable, and write a simple migration so existing data comes across cleanly.

If you can change a customer's address in one place and see it reflected everywhere, your schema is doing its job.

Normalisation rewards patience rather than cleverness. Ten minutes spent deciding where a postcode belongs will save hours of reconciliation later, and your future self — the one writing reports at month end — will thank you for it.

Photo: PIX1861 / Pixabay

Related Posts

Developer Laptop Setup Checklist for New UK Hires
Tools

October 10, 2026

Developer Laptop Setup Checklist for New UK Hires

A practical checklist for setting up a secure, comfortable development laptop as a new UK hire, from disk encryption and access requests...

read more
How to Run Zero-Downtime Database Migrations
Databases

October 07, 2026

How to Run Zero-Downtime Database Migrations

Practical steps for changing production schemas without downtime: the expand-and-contract pattern, lock-aware statements, deploy...

read more
PostgreSQL vs MySQL for UK SaaS Startups: A Practical Comparison
Databases

October 05, 2026

PostgreSQL vs MySQL for UK SaaS Startups: A Practical Comparison

PostgreSQL and MySQL both suit UK SaaS products. This comparison looks at scaling behaviour, UK data protection duties and managed...

read more