KAHIBARO
Discord Login Register

9.11. Normalization

Why Normalization Matters

When you design a relational database, one of your main goals is to avoid data problems such as:

Normalization is a set of rules and techniques that help you design tables that store each piece of data in the right place, in a clean and consistent way.

In this chapter you will:

You will not learn SQL syntax here, only how to structure tables. SQL is covered elsewhere in the course.

Key idea: Normalization is about structuring tables so that:

  • Each fact is stored once
  • Data is consistent
  • Changes are easy and safe

Types of Anomalies Normalization Solves

Before looking at normal forms, it helps to see the problems that normalization prevents. These are called anomalies.

Insertion Anomalies

An insertion anomaly happens when you cannot insert data because some other data is missing.

Example table: StudentCourse

student_idstudent_namecourse_idcourse_name
1Alice101Databases
2Bob102Web Development

Problem: You want to add a new course that has no students yet.

To insert a new course row, you need to fill student_id and student_name. You might use a fake student id or leave it NULL. Both options are bad.

This is an insertion anomaly. You should be able to insert a course independently of any students.

Update Anomalies

An update anomaly happens when you must update the same piece of information in multiple rows, and you might miss some.

Continue with the same table. Suppose course 101 changes name from "Databases" to "Database Systems".

student_idstudent_namecourse_idcourse_name
1Alice101Databases
3Carol101Databases

You must update course_name to "Database Systems" in all rows that have course_id = 101. If you miss one row, your data becomes inconsistent.

This is an update anomaly.

Deletion Anomalies

A deletion anomaly happens when deleting one fact accidentally removes other important data.

Using the same StudentCourse table, suppose the only student in course 102 is Bob:

student_idstudent_namecourse_idcourse_name
2Bob102Web Development

If Bob leaves the school and you delete his row, you also delete the only record of course 102. Now it looks like the course never existed.

This is a deletion anomaly.


First Normal Form (1NF)

First Normal Form is the most basic level of normalization. Almost all relational databases expect you to be in 1NF.

Definition of 1NF

A table is in First Normal Form (1NF) if:

  1. Every cell contains a single value, not a list or set.
  2. Each column contains values of the same type.
  3. Each row is uniquely identifiable by a primary key.

1NF rule: No repeating groups or arrays inside a single column. One value per cell.

Example of a Table Not in 1NF

Imagine a Customer table:

customer_idnamephones
1Alice+1-111-1111,+1-2222
2Bob+1-333-3333

Problems:

This violates 1NF.

Converting to 1NF Using a Separate Table

Correct design:

Customer

customer_idname
1Alice
2Bob

CustomerPhone

customer_idphone
1+1-111-1111
1+1-2222
2+1-333-3333

Now:

Repeating Groups Example

Another bad 1NF design:

order_idcustomer_iditem1_nameitem1_qtyitem2_nameitem2_qty
110Apple2Banana5

Issues:

Correct 1NF design:

Order

order_idcustomer_id
110

OrderItem


order_iditem_namequantity
1Apple2
1Banana5

Functional Dependencies (Intuition)

To understand higher normal forms, you need the idea of a functional dependency. This sounds abstract, but the idea is simple.

A functional dependency written as:

$$ A \rightarrow B $$

means: if you know A, you can uniquely determine B.

For example, in a Student table:

In a Product table:

In a CourseEnrollment table:

student_idcourse_idgrade

The pair (student_id, course_id) might uniquely determine grade.

This pair can be the primary key. A primary key always functionally determines all other columns in its table.

You do not need to master the theory here. You only need to recognize when:

This is what 2NF and 3NF care about.


Second Normal Form (2NF)

2NF builds on 1NF. It only matters when your primary key is composite, meaning it uses multiple columns together as the key.

Definition of 2NF

A table is in Second Normal Form (2NF) if:

  1. It is already in 1NF.
  2. Every non key column depends on the whole primary key, not just part of it.

If a non key column depends only on part of a composite key, that column is in the wrong table.

2NF rule: No partial dependencies.
No non key column should depend on just a part of a composite primary key.

Example of a Table Not in 2NF

Consider this Enrollment table:

student_idcourse_idstudent_namecourse_namegrade
1101AliceDatabasesA
2101BobDatabasesB
1102AliceWeb DevA-

Primary key: (student_id, course_id)
Non key columns: student_name, course_name, grade

Look at the dependencies:

So student_name and course_name depend only on part of the composite key, which violates 2NF.

This leads to:

Converting to 2NF

Split the table into three:

Student

student_idstudent_name
1Alice
2Bob

Course

course_idcourse_name
101Databases
102Web Dev

Enrollment

student_idcourse_idgrade
1101A
2101B
1102A-

Now all non key columns in each table depend on the whole primary key of that table:

Third Normal Form (3NF)

3NF builds on 2NF and focuses on removing indirect dependencies.

Definition of 3NF

A table is in Third Normal Form (3NF) if:

  1. It is in 2NF.
  2. Every non key column depends directly on the primary key, not on another non key column.

If a non key column depends on another non key column, you have a transitive dependency, which 3NF forbids.

3NF rule: No transitive dependencies.
Non key columns must depend only on the primary key, not on other non key columns.

Example of a Table Not in 3NF

Consider an Employee table:

employee_idemployee_namedepartment_iddepartment_name
1Alice10Sales
2Bob20IT
3Carol10Sales

Primary key: employee_id
Non key columns: employee_name, department_id, department_name

Dependencies:

Here, department_name does not depend directly on employee_id.
Instead, you have an indirect chain:

$$ employee\_id \rightarrow department\_id \rightarrow department\_name $$

This is a transitive dependency. It causes:

Converting to 3NF

Split the table:

Employee

employee_idemployee_namedepartment_id
1Alice10
2Bob20
3Carol10

Department

department_iddepartment_name
10Sales
20IT

Now:

No non key column depends on another non key column in the same table.

Another 3NF Example: Address Data

Bad 3NF design for Customer:

customer_idnamecityzip_code
1AliceLondon12345
2BobLondon12345
3CarolBristol54321

Suppose zip_code uniquely identifies the city, so:

But in this table:

city depends transitively on customer_id. To be strict 3NF, you might separate:

Customer

customer_idnamezip_code
1Alice12345
2Bob12345
3Carol54321

ZipCode

zip_codecity
12345London
54321Bristol

In practice, many applications leave city and zip in the same table, because the practical benefit of further normalization is small compared to the extra joins. This leads to the next topic: trade offs.


Higher Normal Forms (Brief Overview)

There are more advanced normal forms:

For most typical backend applications:

For this course, you only need a basic awareness that they exist, not to apply them daily.


Step by Step Normalization Example

Let us normalize a realistic table step by step. Suppose we start with a single table:

OrderFull

order_idorder_datecustomer_idcustomer_namecustomer_cityproduct_idproduct_nameunit_pricequantity
12024-01-0110AliceLondon100Keyboard30.002
12024-01-0110AliceLondon101Mouse10.001
22024-01-0211BobBristol100Keyboard30.001

Assume the primary key is (order_id, product_id).

Step 1: Ensure 1NF

Is this in 1NF?

So this table is already in 1NF.

Step 2: Check 2NF (Partial Dependencies)

Primary key: (order_id, product_id)
Non key columns: order_date, customer_id, customer_name, customer_city, product_name, unit_price, quantity

Check dependencies:

Partial dependencies:

So OrderFull is not in 2NF.

Split into separate tables

We can identify at least three entities:

Create these tables:

Customer

customer_idcustomer_namecustomer_city
10AliceLondon
11BobBristol

Product

product_idproduct_nameunit_price
100Keyboard30.00
101Mouse10.00

Order

order_idorder_datecustomer_id
12024-01-0110
22024-01-0211

OrderItem

order_idproduct_idquantity
11002
11011
21001

Now, in each table:

So these tables are in 2NF.

Step 3: Check 3NF (Transitive Dependencies)

Check each table:

Customer

Product

Order

OrderItem

So our final design is in 3NF and avoids the anomalies:

Normalization vs Performance: Trade Offs

Normalization improves data quality but can increase the number of joins in queries.

For example, to get an order summary, you might need:

This is fine in many systems, but in very high traffic scenarios you might:

Examples of intentional denormalization:

Practical rule:

  • Use normalization (up to 3NF) as your default when designing a schema.
  • Denormalize only when you have a clear reason, such as performance, and you understand how to keep data consistent.

How To Use Normalization When Designing Schemas

When you design a new set of tables, you can follow this checklist:

  1. List the facts you need to store.
    Example: "Order has a customer, date, items, quantities, and prices."
  2. Find the primary key for each table.
    Example: order_id for order, (order_id, product_id) for order items.
  3. Check 1NF
    • Any columns with multiple values in one cell?
    • Any repeating groups like phone1, phone2?
  4. Check 2NF
    • If a table has a composite primary key, do any non key columns depend on only part of the key?
  5. Check 3NF
    • In each table, does any non key column depend on another non key column?
  6. If yes, split the table to remove the dependency.

Summary

With this understanding, you can design safer, more maintainable database schemas for your backend applications.

Views: 7

Comments

Please login to add a comment.

Don't have an account? Register now!