Core CS · DBMS
One fact, stored in exactly one place
Normalisation is not a ritual to memorise. It is a repair procedure: find a fact the table stores more than once, give it a table where it is the key, and a whole class of bugs stops being possible.
Split a messy table, step by step →01 The idea
Redundancy is not a space problem
Students are told normalisation saves disk. It barely does. The table in this lesson shrinks from 35 cells to 34 when you normalise it fully — one cell saved. What actually changes is that after the split, no two rows can disagree with each other, because no fact is written twice.
Every rule works on one idea: the functional dependency. Written X → Y, it says that any two rows agreeing on X must agree on Y. A student ID determines a name. A course code determines a course title. An instructor determines the room they sit in. Once you can list those arrows for a table, normalisation stops being a set of definitions to recite and becomes a checklist: for each arrow, ask whether its left-hand side is the key of the table it sits in. If it is not, that arrow is telling you where the next table goes.
02 Worked example
One enrolment table, and the three things it gets wrong
Three students, three courses, five enrolments. The table is already flat — one value per cell — so it is in 1NF. Its key is the pair {SID, CID}: S1 appears on two rows and C1 appears on two rows, so neither column identifies a row alone, and the five pairs are all distinct. Amber marks a cell that repeats something an earlier row already said.
| SID | Name | CID | Course | Instructor | Room | Marks |
|---|---|---|---|---|---|---|
| S1 | Asha | C1 | DBMS | Rao | R101 | 78 |
| S1 | Asha | C2 | OS | Iyer | R204 | 65 |
| S2 | Ravi | C1 | DBMS | Rao | R101 | 71 |
| S3 | Meera | C2 | OS | Iyer | R204 | 82 |
| S3 | Meera | C3 | Networks | Rao | R101 | 90 |
Nine amber cells out of thirty-five. The dependencies that produce them are SID → Name, CID → Course, Instructor and Instructor → Room. Only {SID, CID} → Marks uses the whole key, and Marks is the only non-key column that never restates something an earlier row already said. Now watch what those nine cells cost.
Read the arrows, not the table. Each one is named by its left-hand side. SID → Name hangs off half the key, so it forces a table out at 2NF. Instructor → Room hangs off a non-key column, so it forces one out at 3NF. Repeated cells fall 9 → 7 → 1 → 0 as you go, while the number of distinct facts stays at 16 the whole way — nothing was dropped, which is why the four tables rejoin to exactly the original five rows.
03 Mechanics
Four tests, and the split each one forces
Each normal form is one test applied to one dependency. Run them in order, because each assumes the one before it has already passed. The right-hand column is what the test costs you when you skip it — that is the part interviewers push on.
| Normal form | The test | What failed here | The split it forces |
|---|---|---|---|
| 1NF | one value per cell | Courses held "C1, C2" | one row per (SID, CID) pair — 3 rows became 5 |
| 2NF | nothing depends on part of a composite key | SID → Name | STUDENT(SID, Name) |
| 2NF | nothing depends on part of a composite key | CID → Course, Instructor | COURSE(CID, Course, Instructor, Room) |
| 3NF | no non-key column determines another | Instructor → Room | INSTRUCTOR(Instructor, Room) |
| BCNF | every determinant is a candidate key | nothing — all four pass | no further split needed |
Before — one table
ENROLMENT SID * key Name -- SID → Name CID * key Course -- CID → Course Instructor -- CID → Instructor Room -- Instructor → Room Marks -- {SID,CID} → Marks-- 5 rows · 35 cells · 9 repeated
After — four tables in 3NF
STUDENT(SID*, Name)COURSE(CID*, Course, Instructor)INSTRUCTOR(Instructor*, Room)ENROLMENT(SID*, CID*, Marks) COURSE.Instructor → INSTRUCTORENROLMENT.SID → STUDENTENROLMENT.CID → COURSE-- 13 rows · 34 cells · 0 repeated
SID → Name forced the STUDENT table. Name depended on half the key, so it was rewritten once per course the student took. In STUDENT, SID is the whole key, so the name is stored exactly once and SID stays behind in ENROLMENT as a foreign key.
CID → Course, Instructor forced the COURSE table. Same partial dependency, other half of the key. Room travels with them at this stage: it depends on CID too, just not directly, and it has nothing to do with a student's mark.
Instructor → Room forced the INSTRUCTOR table. After the 2NF split, COURSE still wrote R101 twice, because CID determines Instructor and Instructor determines Room. Room reached the key only through a non-key column, which is what "transitive" means.
Nothing forced a fourth split. A determinant is the left side of an arrow. In the four tables above every determinant — SID, CID, Instructor, {SID, CID} — is the key of the table it sits in, so the schema is already in BCNF. That is the usual outcome; a 3NF table that is not in BCNF needs two overlapping candidate keys, which is rare.
05 Cheat sheet
Four forms, four tests, four costs
| Normal form | Test to apply | What ignoring it costs you |
|---|---|---|
| 1NF | one atomic value per cell, no repeating group | You cannot index, join or constrain a list stuffed into a cell. |
| 2NF | no non-key column depends on only part of a composite key | Insertion and deletion anomalies on whatever that part describes. Free if the key is a single column. |
| 3NF | no non-key column depends on a non-key column | Update anomalies on the chained fact — the same value in many rows. |
| BCNF | every determinant is a candidate key | Rarely anything, and reaching it can cost you a dependency you can no longer check inside one table. |
06 Where & why
Where 3NF is the default, and where it is deliberately abandoned
Normalisation is not a virtue you apply everywhere. It is a trade you make once you know the workload: a normalised schema is cheap to write and expensive to read, and a denormalised one is the reverse. Real systems pick per workload, and they pick knowingly.
An orders schema keeps customers, addresses, products and line items in separate tables. A customer changes their phone number in one row, and every order ever placed shows the new number because none of them copied it.
A star schema repeats product name and category on every row of a wide dimension table. That is redundancy, and it is accepted: data arrives in controlled batch loads rather than ad-hoc updates, so nobody can update two of three copies.
An order document that embeds its line items is a repeating group by 1NF's standard. It is the right call when the items are only ever read with the order, and the wrong one the moment you need to query items on their own.
A materialised view or nightly summary table holds the flat, pre-joined shape reports want. The normalised tables remain the single source of each fact, so a wrong copy is a refresh bug you can rebuild away, not corrupted data.
07 Interview questions
What they actually ask
Normalisation is the most asked DBMS topic in placement interviews and the most commonly recited without understanding. Expect to be handed a table and asked to name its key, its dependencies and its normal form, in that order.
What is normalisation, in one line?
What is a functional dependency?
How do you find the candidate key of a table?
What are the three anomalies, with an example of each?
What is 1NF, and what does it cost you?
What is 2NF, and what is a partial dependency?
What is 3NF, and what is a transitive dependency?
3NF versus BCNF — what is the actual difference?
A table has a single-column primary key. Which forms does it get for free?
How do you know a decomposition did not lose data?
When would you deliberately not normalise?
08 Practice problems
Six schemas to take apart
For every one: write the functional dependencies first, then the candidate key, then the normal form. Decomposing before you have the arrows written down is how people produce tables that will not rejoin.