DBMS slides 📂 Functional Dependencies & Normalization · 6 of 9 42 min read

Database Normalization Made Simple: 1NF, 2NF, 3NF Solved Step by Step

Database normalization turned into a repeatable recipe. This tutorial solves three real problems — Employee–Project, University Classroom, and Student–Course — end to end, transforming each messy "fat table" through 1NF, 2NF, and 3NF. Learn to find the candidate key, kill partial and transitive dependencies, and build a lossless, foreign-key-linked schema. Includes animated diagrams, full sample tables, and ready-to-run SQL.

Normalization, Solved Step by Step

Turn one messy "fat table" into a clean, anomaly-free design — 1NF → 2NF → 3NF — worked end to end on three real problems. "Every non-key attribute depends on the key, the whole key, and nothing but the key — so help me Codd."
1NF · 2NF · 3NF Decompose 3 Worked Problems SQL Schema

Press Next → or use ← → arrow keys

The Problem

The Receptionist's Notebook

One giant table holding everything
Imagine an organization that records all of its data — employees, departments, projects, managers, hours — in a single sprawling sheet. It feels simple, but the moment you try to add, change, or remove a fact, the design fights back with three anomalies.
➕
Insertion
Can't add cleanly — you can't store a new project or course until some employee or student exists to "carry" it.
✏️
Update
Change in many places — one real fact (a manager's name, a room's capacity) is duplicated across many rows.
🗑️
Deletion
Lose facts by accident — deleting the last employee on a project also deletes the only record it ever existed.
🧭
The One Rule Behind Everything

A non-key attribute must depend on the key, the whole key, and nothing but the key. Those three clauses are 1NF, 2NF, and 3NF.

Foundations

The Vocabulary You Need First

➡️
Functional dependency (A → B)
The value of A uniquely determines B. Know the EmpID, and you know the EmpName. Points one way only.
🔑
Candidate key
A minimal set of attributes that determines every other attribute. The chosen one becomes the primary key.
🟢
Prime vs non-prime
Prime = part of some candidate key. Non-prime = not. The 2NF/3NF rules govern non-prime attributes.
🎯
Find the key first
Every normal-form rule is phrased relative to the key. Identify the candidate key before you normalize anything.
💡
Why Normalize At All?

Goal: one fact in exactly one place. That kills redundancy, removes the three anomalies, and lets foreign keys enforce integrity automatically.

The Two Villains

Partial vs Transitive Dependency

PARTIAL — 2NF forbids A B key = {A, B} non-prime X depends on ½ the key TRANSITIVE — 3NF forbids Key X Y Y reaches key only via X (non-key)
➗
Partial dependency

A non-prime attribute depends on only part of a composite key. Only possible with multi-column keys. 2NF forbids it.

⛓️
Transitive dependency

A non-prime attribute depends on another non-prime attribute (Key → X → Y). 3NF forbids it.

The Ladder

Three Normal Forms at a Glance

1NFSingle, atomic valuesNo lists · no repeating groups 2NFIn 1NF + no partial dep.Depend on the WHOLE key 3NFIn 2NF + no transitive dep.Depend on NOTHING BUT the key
🪜
Each Rung Inherits the Last

1NF ensures atomicity → 2NF removes partial dependencies → 3NF removes transitive dependencies. You can't skip a rung, and every form keeps the guarantees of the one below it.

Problem A · Setup

Employee–Project — The Fat Table

EmpIDEmpNameEmpPhonesDeptIDDeptNameProjIDProjNameMgrIDMgrNameHrs
E01Rakesh98770-11111, 98770-22222D10FinanceP101Budget AppM15Arvind40
E02Ramesh98770-11178D10FinanceP102Billing SysM18Suman35
🔗
The Dependencies

EmpID→EmpName, DeptID · DeptID→DeptName · ProjID→ProjName, MgrID · MgrID→MgrName · {EmpID, ProjID}→Hrs

🔑
Candidate Key

{EmpID, ProjID} — because Hrs needs both. Prime = EmpID, ProjID; everything else is non-prime.

Problem A · Step 1

1NF — Make Every Cell Atomic

Violation: EmpPhones holds a list. Fix: lift phones into their own table, one phone per row.

EmpProject (1NF) · PK {EmpID, ProjectID}
EmpIDProjIDEmpNameDeptIDDeptNameProjNameMgrIDMgrNameHrs
E01P101RakeshD10FinanceBudget AppM15Arvind40
E02P102RameshD10FinanceBilling SysM18Suman35
EmpPhone (1NF) · PK {EmpID, EmpPhone}
EmpIDEmpPhone
E0198770-11111
E0198770-22222
E0298770-11178
✅
Now in 1NF

Every cell holds a single value. The multivalued list became a separate relation with a composite key {EmpID, EmpPhone} — the standard 1NF move.

Problem A · Step 2

2NF — Kill the Partial Dependencies

Key is {EmpID, ProjID}, but many columns depend on only half of it. Split by which key-part each group needs.

EmpProjectpartial deps Employee (EmpID)Name · DeptID · DeptName Project (ProjID)ProjName · MgrID · MgrName Assignment {EmpID,ProjID}HoursWorked EmpPhone {EmpID,Phone}carried forward from 1NF
➗
Partial Dependencies Found

EmpName, DeptID, DeptName → depend on EmpID only. ProjName, MgrID, MgrName → depend on ProjID only. Only Hrs depends on the whole key. Each group moves to its own table.

Problem A · Step 3

3NF — Remove the Middle-Man

Transitive chains: EmpID→DeptID→DeptName and ProjID→MgrID→MgrName. Lift each non-key determinant into its own table.

Employee
EmpIDNameDeptIDFK
E01RakeshD10
E02RameshD10
Department
DeptIDDeptName
D10Finance
Project
ProjIDProjNameMgrIDFK
P101Budget AppM15
P102Billing SysM18
Manager
MgrIDMgrName
M15Arvind
M18Suman
Assignment
EmpIDProjIDHrs
E01P10140
E02P10235
EmpPhone
EmpIDPhone
E01…11111
E01…22222
E02…11178
🎯
Six Clean Tables — Fully in 3NF

Employee · Department · Project · Manager · Assignment · EmpPhone. Every fact now lives in exactly one place, linked by foreign keys — and the join rebuilds the original losslessly.

Problem A · Schema

The 3NF Schema in SQL

CREATE TABLE Department (
    DeptID    VARCHAR(10) PRIMARY KEY,
    DeptName  VARCHAR(50)
);
CREATE TABLE Manager (
    ManagerID    VARCHAR(10) PRIMARY KEY,
    ManagerName  VARCHAR(50)
);
CREATE TABLE Employee (
    EmpID   VARCHAR(10) PRIMARY KEY,
    EmpName VARCHAR(50),
    DeptID  VARCHAR(10) REFERENCES Department(DeptID)
);
CREATE TABLE Project (
    ProjectID VARCHAR(10) PRIMARY KEY,
    ProjName  VARCHAR(50),
    ManagerID VARCHAR(10) REFERENCES Manager(ManagerID)
);
CREATE TABLE EmpPhone (
    EmpID    VARCHAR(10) REFERENCES Employee(EmpID),
    EmpPhone VARCHAR(20),
    PRIMARY KEY (EmpID, EmpPhone)
);
CREATE TABLE Assignment (
    EmpID       VARCHAR(10) REFERENCES Employee(EmpID),
    ProjectID   VARCHAR(10) REFERENCES Project(ProjectID),
    HoursWorked INT,
    PRIMARY KEY (EmpID, ProjectID)
);
🔗
Foreign Keys = Referential Integrity for Free

The REFERENCES clauses make the database enforce that every DeptID, ManagerID, EmpID and ProjectID actually exists — no orphaned rows, no accidental deletions.

Problem B · Setup

University Classroom — A Key Twist

ClassIDDayTimeSlotCourseIDCourseNameInstrIDInstrNameRoomIDRoomLocCap
C01Mon10–11 AMCS101ProgrammingI10Dr. MehtaR12Block A40
C02Tue9–11 AMCS102Data StructI12Dr. VermaR15Block B60
🔑
The Candidate Key Is Wider Than It Looks

The key is {ClassID, Day, TimeSlot} — Day and TimeSlot can't be derived from anything else. Yet every descriptive column depends on ClassID alone. That's a textbook partial dependency waiting for 2NF.

📞
And a 1NF Problem Too

Instructor phones are multivalued (98760-11111, 98760-22222) — so Step 1 extracts an InstructorPhone table first.

Problem B · 1NF → 3NF

Same Recipe, Six Final Tables

1️⃣
1NF
Extract multivalued phones → InstructorPhone{InstrID, Phone}. Allocation keeps {ClassID, Day, TimeSlot}.
2️⃣
2NF
Descriptions depend on ClassID only → split into ClassDetails(ClassID …) + Schedule(ClassID, Day, TimeSlot).
3️⃣
3NF
Break the Course / Instructor / Room chains into their own tables — each determinant gets its own home.
Final table (3NF)Primary keyHolds
ClassClassIDCourseID FK, InstructorID FK, RoomID FK
CourseCourseIDCourseName
InstructorInstructorIDInstructorName
InstructorPhone{InstructorID, Phone}Inst_Phone
RoomRoomIDRoomLocation, RoomCapacity
Schedule{ClassID, Day, TimeSlot}(the timetable itself)
Problem C · Setup

Student–Course — The Instructor Chain

SIDStudentNameStudentPhonesCourseIDCourseNameInstrIDInstrNameInst_DeptEnrollDate
S001Anil98765-11111, 98765-22222C102OSI11Dr. SinghCS2025-08-05
S002Ayush99900-33333C101DBMSI10Dr. RaoCS2025-08-01
🔗
Dependencies

SID→Name, Phone · CourseID→CourseName, InstrID, InstrName, Inst_Dept · {SID, CourseID}→EnrollDate

⛓️
The Hidden Chain

CourseID → InstrID → (InstrName, Inst_Dept) — instructor facts belong to the instructor, not the course. A transitive dependency for 3NF.

Problem C · 1NF → 3NF

Decomposed to Five Clean Tables

Student
SIDName
S001Anil
S002Ayush
StudentPhone
SIDFKPhone
S001…11111
S001…22222
S002…33333
Course
CourseIDNameInstrIDFK
C102OSI11
C101DBMSI10
Instructor
InstrIDNameDept
I11Dr. SinghCS
I10Dr. RaoCS
Enrollment
SIDFKCourseIDFKEnrollDate
S001C1022025-08-05
S002C1012025-08-01
✅
Instructor facts, once

"Dr. Singh / CS" now lives in one row.

The Pattern

One Recipe That Solved All Three

Raw fat tablefind candidate key 1NFatomic values 2NFno partial dep. 3NFno transitive dep. the same four moves — every single time
🔁 THE REPEATABLE PROCEDURE
1
Identify the candidate key — every rule is phrased relative to it.
2
1NF: pull multivalued cells / repeating groups into their own table with a composite key.
3
2NF: if the key is composite, move each part-key-dependent group to its own table.
4
3NF: lift every non-key determinant (the "middle-man") into its own table, leaving an FK behind.
Perspective

Academic vs Industry Lenses

🎓
Academic lens
Each normal form is a theorem phrased over functional dependencies and candidate keys. Decomposition is provably lossless and dependency-preserving — the goal is anomaly-free by proof.
🏭
Industry lens
Less storage, safer writes: one fact, one place. Foreign keys enforce integrity automatically. OLTP systems normalize to 3NF/BCNF; analytics deliberately denormalize into star schemas for read speed.
⚖️
The Trade-Off

Normalization optimizes write integrity but adds read-time joins. Transactional systems stay at 3NF; data warehouses relax it on purpose — a measured decision, never an accident.

Cheat Sheet

Six Golden Rules of Normalization

🏆 CARRY THESE INTO EVERY DESIGN
1
Find the candidate key first. Every normal-form rule is phrased relative to the key.
2
1NF kills multivalued cells. Comma-separated lists become separate tables with composite keys.
3
2NF only applies to composite keys. A single-attribute key in 1NF is automatically in 2NF.
4
3NF hunts the middle-man. Lift non-key determinant attributes into their own tables.
5
Decomposition must be lossless. The shared attribute must be a key in at least one table.
6
Each step inherits the last. Carry forward already-separated tables — never re-merge them.
FINAL

One Fact, One Place

1NFAtomic values
2NFNo partial deps
3NFNo transitive deps
3Problems solved
🎯
Normalization Is a Discipline, Not a Guess

Across Employee–Project, University Classroom, and Student–Course, the same four moves turned a redundant fat table into well-formed relations: find the key → atomize (1NF) → remove partial deps (2NF) → remove transitive deps (3NF). The payoff is a schema where every fact exists exactly once and foreign keys guard its integrity.

🧠
One Sentence to Remember

Every non-key attribute must depend on the key, the whole key, and nothing but the key — so help me Codd.

🗄️ End of tutorial · Press ← to review, or click Restart