Visual walkthrough — Normalization — 1NF, 2NF, 3NF, BCNF — anomalies each resolves
Before any symbol appears, three words we will lean on the whole way:
We also need the arrow. When we write (read " arrow ") we mean: knowing pins down . If two rows show the same , they are forced to show the same . That arrow is our only piece of notation; everything else is grids and colours. (Full treatment: Functional Dependencies.)
Step 1 — The table we start with
WHAT. A school stuffs everything about enrollments into ONE table:
Term by term, what each column is:
- — the code for a student (S1, S2, …). Underlined = part of the key.
- — the code for a course (C1, C2, …). Also underlined = part of the key.
- — the student's human name.
- — the mark that student got in that course.
- — the teacher who advises that student.
- — the department that advisor belongs to.
WHY start here. This table looks tidy but is secretly three facts glued together: "who a student is", "what grade they got", "which department advises them". We will pry them apart.
PICTURE. Look at the grid. The pink columns repeat the same value every time a student appears — that repetition is the enemy.

Step 2 — 1NF: make every cell atomic
WHAT. Suppose someone had stored the phones as one cell: . Atomic means one value per cell — no lists hiding inside.
WHY this tool, why now. Before we can even talk about which column determines which, each cell must hold exactly one thing. A list in a cell is invisible to the database: you cannot ask "who owns 9992?" because 9992 is buried in text. So the very first repair is: explode every list into its own rows.
PICTURE. On the left, one row with a two-item cell. On the right, two rows, each with a single phone. Same facts — now reachable.

Step 3 — Spot the partial dependency (the 2NF offender)
WHAT. Ask of each non-key column: does it really need the whole key, or just part of it?
- needs both and (a grade is per student per course). Good — full key.
- needs only . The course is irrelevant to your name.
So we have found a partial dependency:
- — a proper subset of the key (proper = strictly smaller, leaves out ).
- The arrow — "determines": same forces same .
- — a non-prime column (belongs to no key), so it is the kind of column the rule protects.
WHY this is a bug. Ana takes 4 courses → her name is written 4 times. Rename her and you must fix all 4 rows; miss one → the table disagrees with itself (update anomaly). Drop her last enrollment → her name vanishes entirely (delete anomaly).
PICTURE. The arrow reaches from only half the key. Watch the blue cell repeat down the rows — that column is copied, wastefully.

Step 4 — 2NF: split the partial dependency out
WHAT. Carve into its own table, keyed by the part it actually depends on:
WHY it works. Now each student's name is stored once in . keeps only what genuinely needs the whole pair-key () plus the advisor columns we still owe attention to. The join back is lossless because is the shared link (see Decomposition — Lossless Join and Dependency Preservation).
PICTURE. The blue name column lifts out of the big grid into a small 2-column table. Where four "Ana" cells stood, one remains.

Step 5 — Spot the transitive dependency (the 3NF offender)
WHAT. Look inside the new at the advisor columns. Two real rules:
Chain them:
This chain means transitively — the key reaches only through the non-key middleman . (For simplicity here read as the determinant; the point is the middleman is not a key.)
- The middle arrow's left side, , is not a superkey — it does not identify a row of Enroll.
- is non-prime — belongs to no candidate key.
- Both conditions true at once ⇒ 3NF is violated.
WHY this is a bug. Every student advised by teacher T repeats T's department. Move the advisor's department once in the real world → hunt down every student row (update anomaly). The last student of an advisor leaves → the advisor's department is lost (delete anomaly).
PICTURE. A two-hop arrow: key → middleman → tag-along. The yellow cell repeats for every student of the same advisor.

Step 6 — 3NF: cut the chain at the middleman
WHAT. Give the middleman its own table:
WHY it works. Now lives once per advisor. keeps only as a pointer. The chain is broken: nothing non-key determines another non-key anymore.
PICTURE. The yellow department column detaches into a tiny table; Enroll keeps just the arrow-pointer .

Step 7 — The BCNF loophole: a table that passes 3NF but still leaks
WHAT. A different corner of the school: who teaches whom.
with two real rules:
- each — a student studies a subject with one teacher.
- each — a teacher teaches exactly one subject.
Work out the keys: from , knowing gives , so is a key. And is a key too. Therefore both and are prime (each sits in some key).
Now test the FD :
- is not a superkey (a teacher alone does not identify a row).
- but is prime → 3NF's escape hatch says "fine!". 3NF passes.
- BCNF has no escape hatch → BCNF fails.
WHY this still bugs. You cannot record "Teacher T teaches Subject Y" until some student enrolls — the row needs a (insert anomaly). The fact "T teaches Y" is homeless.
PICTURE. The FD arrow starts at a non-superkey; the pink cell shows duplicated for every student of that teacher, yet 3NF waves it through because is prime.

Step 8 — BCNF: every determinant must be a superkey
WHAT. Split on the offending determinant :
WHY it works. Now "T teaches Y" lives in with as its key — a determinant that is a superkey. You can register a teacher's subject with no student present. Every remaining FD has a superkey on its left.
PICTURE. becomes its own clean 2-column table; the leftover links students to teachers.

The one-picture summary
Every squeeze is the same move: find an arrow whose left side is too small or non-key, and lift the arrow into its own table. 1NF fixes cells; 2NF fixes "part of key"; 3NF fixes "non-key middleman"; BCNF fixes "any non-superkey determinant".

Recall Feynman retelling of the whole walkthrough
We started with one giant notebook page where a student's name, grade, and advisor's department were all crammed on each enrollment line. 1NF: stop stuffing lists in a box — one thing per box, so you can actually search it. 2NF: the student's name only cares about the student, not the course, yet we rewrote it for every course — so we moved names to their own little "Student" book, written once. 3NF: the advisor's department only cares about the advisor, and the advisor is not the key — a middleman — so we gave advisors their own "Advisor" book. BCNF: in a separate teaching table, a rule "each teacher teaches one subject" duplicated the subject over and over, and 3NF let it slide because "subject" happened to be part of a key — but you still couldn't record a teacher's subject before a student showed up. BCNF says no left-side may be a non-key, so we gave teachers-and-their-subjects their own book too. Each step: spot an arrow starting from something too small, and give that arrow its own page — so every fact is written exactly once.
Recall Quick checks
Why is a partial dependency? ::: is a proper subset of the composite key and is non-prime. Why does violate 3NF? ::: is a non-key middleman and is non-prime — a transitive dependency. Why does pass 3NF but fail BCNF? ::: is not a superkey (fails BCNF) but is prime, so 3NF's "or is prime" hatch excuses it. What is the single repeated move across all forms? ::: Find an arrow whose left side is too small / non-key, and lift it into its own table.