Relationships and Normalization

3.400,000 Copies of One Address

A

In this chapter

We'll learn the three kinds of relationships between tables — one-to-one, one-to-many and many-to-many — and normalization: the habit of storing each fact once, explained with a messy address book.

12–14 min

The Problem in Real Life

The old bookings_archive table has 400,000 rows. Each one repeats the venue's name and address: "Grand Hall, 12 River Road." Last year the venue moved to "14 River Road." Someone updated the address in the venues table — but the 400,000 copies in the archive still say 12. Half of BlueTicket's reports now show one address, half the other.

"The same fact, written in four hundred thousand places," John says. "And of course they don't agree. Let's talk about how tables should relate — and how to write each fact only once."

J

Write each fact once, in one place. Everything else should point to it.

John

Copying Facts Everywhere vs. Linking to Them

Copies drift apart

When the same fact is stored in many places, one update misses some copies — and the data contradicts itself.

Things relate in different ways

An event has many seats; a fan goes to many events; each event has many fans. Each needs a different design.

Relationships and Normalization

Tables link to each other in three shapes. Each has an everyday example that makes it obvious.

  • One-to-one — a person and their passport: each person has one passport, and each passport belongs to one person. In a database: each fan has one settings record. These are less common — often the two could just be one table.
  • One-to-many — a mother and her children: one event has many seats, but each seat belongs to exactly one event. One venue has many events. This is the most common relationship of all. You build it by putting a foreign key on the "many" side: each seat row stores its event_id.
  • Many-to-many — students and classes: one fan can go to many events, and one event has many fans. You can't store this with a single foreign key on either side — a fan row can't hold a list of all their events, and an event row can't hold all its fans. The answer is a third table in the middle, called a junction table (or join table), with one row per link. For BlueTicket, that middle table is bookings: each row says "this fan, this seat (at this event)." Like a class register: one line per student-class pair.
Table — Three kinds of relationships
RelationshipEveryday exampleBlueTicket exampleHow it's built
One-to-oneA person and their passportA fan and their settingsA foreign key, unique
One-to-manyA mother and her childrenAn event and its seatsA foreign key on the "many" side
Many-to-manyStudents and classesFans and eventsA junction table (bookings)
Table — Before normalization: the venue copied into every booking
booking_idfanvenue_namevenue_address
1ZoëGrand Hall12 River Road
2LiamGrand Hall14 River Road
3AvaGrand Hall12 River Road
"venue_address" is a column — every row has this fact

Same venue, two different addresses — the copies drifted apart after the venue moved.

Table — After normalization: the address lives in one place
venues.idnameaddress
3Grand Hall14 River Road

Bookings now store only venue_id = 3. Change the address once, and everything is correct.

Many-to-many: fans and events, through bookings

fans

Zoë (77), Liam (12), ...

events

Comedy Night (42), Festival (57), ...

each link is one row

bookings (junction table)

one row per fan + seat: (77 → seat at 42), (77 → seat at 57), (12 → seat at 42)

Zoë goes to two events; Comedy Night has two fans

many on both sides

Normalization — the messy address book analogy: imagine an address book where every time you write about a friend, you also copy their full address. When they move, you'd need to find and fix every copy — and you'll miss some. A tidy address book stores each friend's address once, and everything else just mentions their name. Normalization is doing this for a database: organise tables so that each fact is stored in exactly one place, and other tables refer to it with a foreign key.

The three problems normalization prevents: update problems — change the venue's address in one place, the copies keep the old one (what happened in the archive). Insert problems — you can't record a new venue until it has a booking, because the venue only exists inside booking rows. Delete problems — delete the last booking at a venue, and you lose the venue's address entirely.

How BlueTicket fixes the archive: the venue's name and address move to the venues table only. The archive's rows keep just venue_id. When the venue moves again, one row changes, and every report is right instantly. Database designers describe tidiness in levels called normal forms (first, second, third...). You don't need the details now — the idea behind all of them is "one fact, one place."

A sensible exception: sometimes a team deliberately copies a value to make reading faster, or to record history. For example, a booking stores the price paid at the moment of purchase, even though the seat has its own price — because if the seat's price changes later, the booking must still show what the fan actually paid. That's a deliberate choice, not an accident — and it has a name: denormalization.

Key Takeaway

Tables relate in three ways: one-to-one (person and passport), one-to-many (an event and its seats — a foreign key on the "many" side), and many-to-many (fans and events — a junction table like bookings in the middle). Normalization means storing each fact once and linking to it, which prevents copies that drift apart.

Why This Matters

Good table design decides whether a system's data stays trustworthy for years or slowly fills with contradictions. Spotting a many-to-many relationship and a repeated fact are two of the most useful database design skills. The Relational Databases course goes through normal forms and relationships in full detail.

The tables are tidy. Now Anna is ready for the real fix: making it impossible for two sales of the same seat to both succeed — even if they arrive in the same millisecond.

Next