19. The Normalization Process: 1NF, 2NF, 3NF¶
Lecture 18 established why normalization matters and introduced its vocabulary — functional dependencies, partial and transitive dependency, lossless-join. This lecture turns that vocabulary into a repeatable procedure and applies it, start to finish, to one running example: a single unnormalized order-tracking table, carried through First, Second, and Third Normal Form until it becomes a clean, anomaly-free set of relations. Work through every step by hand — this is the single most important worked example in the entire normalization unit, and every later lecture (BCNF, 4NF) assumes you can reproduce it.
In This Lecture¶
- First Normal Form (1NF) — atomic values, no repeating groups
- Second Normal Form (2NF) — no partial dependency on a composite key
- Third Normal Form (3NF) — no transitive dependency
- One running example, converted step by step: UNF → 1NF → 2NF → 3NF
- A second, shorter worked example to reinforce the pattern
- Testing for normal forms — the checklist to apply to any relation, not just the running example
The Running Example: An Unnormalized Order Table¶
A sales system needs to record customer orders, and each order can include several products. A first, naive attempt stores one row per order, with the product details for that order packed into a repeating group inside the row:
| orderNo | orderDate | custNo | custName | custAddress | { productNo, productName, unitPrice, qty } |
|---|---|---|---|---|---|
| O100 | 2026-08-01 | C001 | Ann Beech | 12 Elm St, Lahore | { (P01, Widget, 9.99, 3), (P02, Gadget, 24.99, 1) } |
| O101 | 2026-08-02 | C002 | Tom Kelly | 5 Oak Ave, Karachi | { (P01, Widget, 9.99, 2) } |
| O102 | 2026-08-03 | C001 | Ann Beech | 12 Elm St, Lahore | { (P03, Sprocket, 4.50, 10) } |
Order O100's single row is trying to hold two product lines inside one cell — exactly
the "repeating group" Lecture 5 ruled out when it required every attribute value to be
atomic. This table is not yet a valid relation at all; it is Unnormalized Form
(UNF), the raw, pre-relational starting point every normalization exercise begins from.
The functional dependencies that hold, stated informally before any structure is imposed:
orderNo → orderDate, custNo(each order has one date and one customer)custNo → custName, custAddress(each customer has one name and address)productNo → productName, unitPrice(each product has one name and one catalog price)- an order's quantity of a product depends on both which order and which product
First Normal Form (1NF)¶
Definition
A relation is in First Normal Form (1NF) if every attribute holds a single, atomic value — no repeating groups, no nested tables, no multi-valued cells. This is not an extra rule normalization invents; it is simply Lecture 5's definition of a valid relation, restated as the first checkpoint.
Conversion to 1NF¶
The repeating group must be flattened: give each product line its own row, and repeat
the order-level attributes (orderDate, custNo, custName, custAddress) across every
line that belongs to the same order. Since a single orderNo value no longer identifies one
row uniquely — O100 now spans two rows — the primary key must grow to a composite key:
{orderNo, productNo} is the smallest attribute set that uniquely identifies each row.
| orderNo | productNo | orderDate | custNo | custName | custAddress | productName | unitPrice | qty |
|---|---|---|---|---|---|---|---|---|
| O100 | P01 | 2026-08-01 | C001 | Ann Beech | 12 Elm St, Lahore | Widget | 9.99 | 3 |
| O100 | P02 | 2026-08-01 | C001 | Ann Beech | 12 Elm St, Lahore | Gadget | 24.99 | 1 |
| O101 | P01 | 2026-08-02 | C002 | Tom Kelly | 5 Oak Ave, Karachi | Widget | 9.99 | 2 |
| O102 | P03 | 2026-08-03 | C001 | Ann Beech | 12 Elm St, Lahore | Sprocket | 4.50 | 10 |
Every attribute now holds one atomic value, and there are no repeating groups — this is
a valid relation, and it satisfies 1NF. But look at what flattening bought us: orderDate,
custNo, custName, and custAddress are now repeated across both of O100's rows, and
productName/unitPrice for Widget (P01) are repeated across O100 and O101. 1NF
fixed the structural problem (non-atomic values); it did nothing about the redundancy
problem from Lecture 18 — that requires 2NF and 3NF.
Second Normal Form (2NF)¶
Definition
A relation is in Second Normal Form (2NF) if it is already in 1NF, and every non-key attribute is fully functionally dependent on the whole primary key — not on only part of it. A partial dependency exists when a non-key attribute depends on a proper subset of a composite key. (2NF only has anything to check when the primary key is composite; a relation with a single-attribute key is automatically in 2NF once it's in 1NF.)
Testing the 1NF Relation for Partial Dependencies¶
The primary key of the 1NF relation above is the composite {orderNo, productNo}. Check
each non-key attribute against both halves of that key individually:
| Non-key attribute | Depends on orderNo alone? |
Depends on productNo alone? |
Depends on the whole key? |
|---|---|---|---|
orderDate |
Yes (orderNo → orderDate) |
No | Partial — only needs orderNo |
custNo |
Yes (orderNo → custNo) |
No | Partial — only needs orderNo |
custName |
Yes (via custNo) |
No | Partial |
custAddress |
Yes (via custNo) |
No | Partial |
productName |
No | Yes (productNo → productName) |
Partial — only needs productNo |
unitPrice |
No | Yes (productNo → unitPrice) |
Partial |
qty |
No | No | Full — genuinely needs both orderNo and productNo |
Six of the seven non-key attributes are partially dependent on the key — only qty needs
both halves. This relation violates 2NF.
Conversion to 2NF¶
Every partially-dependent attribute must move into a relation keyed by whichever part of
the composite key actually determines it. Attributes depending on orderNo alone move to
an Order relation; attributes depending on productNo alone move to a Product
relation; qty, which genuinely needs the full composite key, stays behind in a
line-items relation that still carries both orderNo and productNo as a foreign key
pair:
| orderNo | orderDate | custNo | custName | custAddress |
|---|---|---|---|---|
| O100 | 2026-08-01 | C001 | Ann Beech | 12 Elm St, Lahore |
| O101 | 2026-08-02 | C002 | Tom Kelly | 5 Oak Ave, Karachi |
| O102 | 2026-08-03 | C001 | Ann Beech | 12 Elm St, Lahore |
| productNo | productName | unitPrice |
|---|---|---|
| P01 | Widget | 9.99 |
| P02 | Gadget | 24.99 |
| P03 | Sprocket | 4.50 |
| orderNo | productNo | qty |
|---|---|---|
| O100 | P01 | 3 |
| O100 | P02 | 1 |
| O101 | P01 | 2 |
| O102 | P03 | 10 |
Each of these three relations is now in 2NF: Product and Order have single-attribute
keys, so partial dependency is structurally impossible; OrderLine's only non-key attribute
(qty) genuinely needs the entire composite key. Widget's price no longer repeats per
order — it lives in exactly one row of Product. But Order still has a problem: does
custName really depend on orderNo, or does it depend on custNo, which merely happens
to be reachable from orderNo? That question is exactly what 3NF answers.
Third Normal Form (3NF)¶
Definition
A relation is in Third Normal Form (3NF) if it is already in 2NF, and no non-key
attribute is transitively dependent on the primary key. A transitive dependency
exists when a non-key attribute Z depends on another non-key attribute Y, and Y in
turn depends on the key X — that is, X → Y → Z, but Z does not depend on X
directly, only through Y.
Testing the 2NF Relations for Transitive Dependencies¶
Product and OrderLine are unaffected — check Order(orderNo, orderDate, custNo,
custName, custAddress), key orderNo:
orderNo → custNo— direct, fine.orderNo → orderDate— direct, fine.custNo → custNameandcustNo → custAddress— butcustNois itself a non-key attribute of this relation (the key isorderNoalone). SocustNameandcustAddressdepend onorderNoonly transitively, throughcustNo:orderNo → custNo → custName. This is exactly the transitive-dependency pattern the definition above describes, and it violates 3NF.
The practical symptom is the redundancy already visible in the table: Ann Beech and her
address are stored once per order she places (O100 and O102 both repeat them), because
the fact "which customer" and the fact "that customer's name and address" are bundled into
one relation even though they describe two different things.
Conversion to 3NF¶
Split off the transitively-dependent attributes into their own relation, keyed by the
attribute they actually depend on (custNo), leaving only custNo behind in Order as a
foreign key:
| custNo | custName | custAddress |
|---|---|---|
| C001 | Ann Beech | 12 Elm St, Lahore |
| C002 | Tom Kelly | 5 Oak Ave, Karachi |
| orderNo | orderDate | custNo |
|---|---|---|
| O100 | 2026-08-01 | C001 |
| O101 | 2026-08-02 | C002 |
| O102 | 2026-08-03 | C001 |
Product and OrderLine from the 2NF step carry over unchanged. The final schema —
verified 3NF, and in fact BCNF as well (every determinant in every relation below is that
relation's key, which Lecture 20 will show is the sharper test):
Customer (custNo, custName, custAddress)
Product (productNo, productName, unitPrice)
Order (orderNo, orderDate, custNo)
Foreign Key custNo references Customer(custNo)
OrderLine (orderNo, productNo, qty)
Foreign Key orderNo references Order(orderNo)
Foreign Key productNo references Product(productNo)
UNF to 3NF, the whole journey
UNF One row per order, product lines repeat inside it
1NF Flattened — one row per (order, product); key grows composite
2NF Split off attributes depending on only half the composite key
3NF Split off attributes depending on a non-key attribute, not the key itself
Every anomaly from Lecture 18 is now gone: Product accepts a new, unordered product;
deleting O101 leaves Customer row C002 intact; Widget's price lives in exactly one
row. And it cost nothing in information — Customer ⋈ Order ⋈ OrderLine ⋈ Product
reconstructs the original flattened 1NF table exactly (the lossless-join property from
Lecture 18), because every join attribute (custNo, orderNo, productNo) is the primary
key of the relation on the "one" side of the join.
Examples of Normalization: A Second, Shorter Pass¶
To confirm the pattern generalizes beyond the order-tracking example, apply the same three questions to a differently-shaped relation: a university records each course enrollment, along with the assigned instructor's office, in one table.
| studentNo | courseNo | studentName | courseName | instructorNo | instructorOffice | grade |
|---|---|---|---|---|---|---|
| S1 | CS201 | Bilal Khan | Databases | I01 | Room 214 | A |
| S1 | CS305 | Bilal Khan | Networks | I02 | Room 108 | B+ |
| S2 | CS201 | Sara Malik | Databases | I01 | Room 214 | A− |
FDs: studentNo → studentName; courseNo → courseName, instructorNo; instructorNo →
instructorOffice; {studentNo, courseNo} → grade.
- 2NF check against key
{studentNo, courseNo}:studentNamedepends onstudentNoalone (partial);courseNameandinstructorNodepend oncourseNoalone (partial);instructorOfficedepends oninstructorNo, which depends oncourseNoalone — also ultimately reachable from justcourseNo(partial); onlygradeneeds the full key. Violates 2NF. Split intoStudent(studentNo, studentName),Course(courseNo, courseName, instructorNo, instructorOffice), andEnrollment(studentNo, courseNo, grade). - 3NF check on the new
Course(courseNo, courseName, instructorNo, instructorOffice), keycourseNo:instructorOfficedepends oninstructorNo, which is itself a non-key attribute ofCourse— transitive. Violates 3NF. Split offInstructor(instructorNo, instructorOffice), leavingCourse(courseNo, courseName, instructorNo).
Final 3NF schema: Student(studentNo, studentName), Instructor(instructorNo,
instructorOffice), Course(courseNo, courseName, instructorNo), Enrollment(studentNo,
courseNo, grade) — the exact same three-question pattern (atomicity, then partial
dependency, then transitive dependency), applied to a different domain, produces the same
kind of clean result.
Testing for Normal Forms¶
Given any relation and its functional dependencies, apply these three questions in order — the moment one fails, stop and fix that level before checking the next:
Testing checklist — apply in order
1. Is every attribute value atomic? No repeating groups, no multi-valued cells. No -> not even in 1NF; flatten first.
2. Is the key composite? If so, does every non-key attribute need the WHOLE key? Single-attribute key -> automatically 2NF. Composite key -> check each non-key attribute against each proper subset of the key.
3. Does every non-key attribute depend ONLY on the key -- never on another non-key attribute? If X (key) -> Y (non-key) -> Z (non-key), Z is transitively dependent -> violates 3NF.
Partial vs. transitive: the most common exam mix-up
Both violations look similar on the page — "this attribute doesn't depend on the whole
key" — but they are structurally different. A partial dependency is about a
composite key: some non-key attribute depends on only part of it. A transitive
dependency can happen even with a single-attribute key: the culprit is a non-key
attribute standing in the way, as in custNo → custName inside a relation keyed by
orderNo. If the key is a single attribute, partial dependency is impossible by
definition — only check for transitive dependency.
Key Takeaways¶
- 1NF: every attribute value is atomic — no repeating groups. Fixed by flattening, which often forces the primary key to become composite.
- 2NF: every non-key attribute depends on the whole composite key, not part of it. Only relevant when the key is composite; fixed by splitting off attributes that depend on only part of the key.
- 3NF: every non-key attribute depends directly on the key, never transitively through another non-key attribute. Fixed by splitting off the non-key attribute doing the determining, along with everything it determines.
- The running
Orderexample went UNF → 1NF → 2NF → 3NF, ending atCustomer,Product,Order,OrderLine— a schema with zero redundancy for any single fact, verified lossless via natural join back to the original flattened table. - Testing any relation for normal forms is the same three-question procedure every time: atomicity, then partial dependency (composite keys only), then transitive dependency — applied in that order, since each level assumes the previous one already holds.
3NF eliminates most real-world redundancy, but it is not the strictest possible test — Lecture 20 introduces Boyce-Codd Normal Form (BCNF), a stronger rule that catches a specific kind of anomaly 3NF can still miss, along with the formal machinery (Armstrong's Axioms, attribute closure) needed to find every candidate key of a relation precisely.