Normalization, Solved Step by Step
Press Next → or use ← → arrow keys
The Receptionist's Notebook
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.
The Vocabulary You Need First
Goal: one fact in exactly one place. That kills redundancy, removes the three anomalies, and lets foreign keys enforce integrity automatically.
Partial vs Transitive Dependency
A non-prime attribute depends on only part of a composite key. Only possible with multi-column keys. 2NF forbids it.
A non-prime attribute depends on another non-prime attribute (Key → X → Y). 3NF forbids it.
Three Normal Forms at a Glance
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.
Employee–Project — The Fat Table
| EmpID | EmpName | EmpPhones | DeptID | DeptName | ProjID | ProjName | MgrID | MgrName | Hrs |
|---|---|---|---|---|---|---|---|---|---|
| E01 | Rakesh | 98770-11111, 98770-22222 | D10 | Finance | P101 | Budget App | M15 | Arvind | 40 |
| E02 | Ramesh | 98770-11178 | D10 | Finance | P102 | Billing Sys | M18 | Suman | 35 |
EmpID→EmpName, DeptID · DeptID→DeptName · ProjID→ProjName, MgrID · MgrID→MgrName · {EmpID, ProjID}→Hrs
{EmpID, ProjID} — because Hrs needs both. Prime = EmpID, ProjID; everything else is non-prime.
1NF — Make Every Cell Atomic
Violation: EmpPhones holds a list. Fix: lift phones into their own table, one phone per row.
| EmpID | ProjID | EmpName | DeptID | DeptName | ProjName | MgrID | MgrName | Hrs |
|---|---|---|---|---|---|---|---|---|
| E01 | P101 | Rakesh | D10 | Finance | Budget App | M15 | Arvind | 40 |
| E02 | P102 | Ramesh | D10 | Finance | Billing Sys | M18 | Suman | 35 |
| EmpID | EmpPhone |
|---|---|
| E01 | 98770-11111 |
| E01 | 98770-22222 |
| E02 | 98770-11178 |
Every cell holds a single value. The multivalued list became a separate relation with a composite key {EmpID, EmpPhone} — the standard 1NF move.
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.
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.
3NF — Remove the Middle-Man
Transitive chains: EmpID→DeptID→DeptName and ProjID→MgrID→MgrName. Lift each non-key determinant into its own table.
| EmpID | Name | DeptIDFK |
|---|---|---|
| E01 | Rakesh | D10 |
| E02 | Ramesh | D10 |
| DeptID | DeptName |
|---|---|
| D10 | Finance |
| ProjID | ProjName | MgrIDFK |
|---|---|---|
| P101 | Budget App | M15 |
| P102 | Billing Sys | M18 |
| MgrID | MgrName |
|---|---|
| M15 | Arvind |
| M18 | Suman |
| EmpID | ProjID | Hrs |
|---|---|---|
| E01 | P101 | 40 |
| E02 | P102 | 35 |
| EmpID | Phone |
|---|---|
| E01 | …11111 |
| E01 | …22222 |
| E02 | …11178 |
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.
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)
);
The REFERENCES clauses make the database enforce that every DeptID, ManagerID, EmpID and ProjectID actually exists — no orphaned rows, no accidental deletions.
University Classroom — A Key Twist
| ClassID | Day | TimeSlot | CourseID | CourseName | InstrID | InstrName | RoomID | RoomLoc | Cap |
|---|---|---|---|---|---|---|---|---|---|
| C01 | Mon | 10–11 AM | CS101 | Programming | I10 | Dr. Mehta | R12 | Block A | 40 |
| C02 | Tue | 9–11 AM | CS102 | Data Struct | I12 | Dr. Verma | R15 | Block B | 60 |
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.
Instructor phones are multivalued (98760-11111, 98760-22222) — so Step 1 extracts an InstructorPhone table first.
Same Recipe, Six Final Tables
| Final table (3NF) | Primary key | Holds |
|---|---|---|
| Class | ClassID | CourseID FK, InstructorID FK, RoomID FK |
| Course | CourseID | CourseName |
| Instructor | InstructorID | InstructorName |
| InstructorPhone | {InstructorID, Phone} | Inst_Phone |
| Room | RoomID | RoomLocation, RoomCapacity |
| Schedule | {ClassID, Day, TimeSlot} | (the timetable itself) |
Student–Course — The Instructor Chain
| SID | StudentName | StudentPhones | CourseID | CourseName | InstrID | InstrName | Inst_Dept | EnrollDate |
|---|---|---|---|---|---|---|---|---|
| S001 | Anil | 98765-11111, 98765-22222 | C102 | OS | I11 | Dr. Singh | CS | 2025-08-05 |
| S002 | Ayush | 99900-33333 | C101 | DBMS | I10 | Dr. Rao | CS | 2025-08-01 |
SID→Name, Phone · CourseID→CourseName, InstrID, InstrName, Inst_Dept · {SID, CourseID}→EnrollDate
CourseID → InstrID → (InstrName, Inst_Dept) — instructor facts belong to the instructor, not the course. A transitive dependency for 3NF.
Decomposed to Five Clean Tables
| SID | Name |
|---|---|
| S001 | Anil |
| S002 | Ayush |
| SIDFK | Phone |
|---|---|
| S001 | …11111 |
| S001 | …22222 |
| S002 | …33333 |
| CourseID | Name | InstrIDFK |
|---|---|---|
| C102 | OS | I11 |
| C101 | DBMS | I10 |
| InstrID | Name | Dept |
|---|---|---|
| I11 | Dr. Singh | CS |
| I10 | Dr. Rao | CS |
| SIDFK | CourseIDFK | EnrollDate |
|---|---|---|
| S001 | C102 | 2025-08-05 |
| S002 | C101 | 2025-08-01 |
"Dr. Singh / CS" now lives in one row.
One Recipe That Solved All Three
Academic vs Industry Lenses
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.
Six Golden Rules of Normalization
One Fact, One Place
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.
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