- Normalization is the process of splitting tables so that each fact is stored in exactly one place.
- A normal form is a stage in that process, and each stage removes one particular kind of dependency problem.
- The forms are cumulative, so a table in 3NF is already in 2NF and 1NF.
- Normalization is worth doing because duplicated data does not stay identical: one copy gets updated and the other does not.
- Normalization is a design activity carried out on the structure, not on the stored records.
- Learning the three forms as definitions to recite is the slow way, because the definitions only make sense once you can see the anomaly each one prevents.
- Update anomaly
- The same fact is stored in many rows, so changing it in one row leaves the others stale and the database now holds two answers to one question.
- Insert anomaly
- A new fact cannot be recorded without inventing unrelated data, so a new item cannot be added to the price list until somebody buys it.
- Delete anomaly
- Removing one row destroys a second, unrelated fact, so deleting the last purchase of an item also deletes the only record of its price.
- One table holds StudentID, StudentName, ItemName and UnitPrice, with a row for every purchase ever made.
- Update: raising the price of a pen means editing every row that mentions a pen, and one missed row leaves two prices in the database.
- Insert: a new pencil case cannot be priced until a student buys one, because there is no row to put it in.
- Delete: deleting Ben Wong's only purchase also deletes the only stored price of a pencil.
Every normal form is defined in terms of dependency, so these terms have to be used exactly.
| Term | Meaning | Example |
|---|
| Atomicity | Every cell holds one single indivisible value | "Pen, Notebook" in one cell is not atomic |
| Unique identification | Every row can be told apart from every other by its key | StudentID identifies exactly one student |
| Functional dependency | Attribute B is functionally dependent on A if one value of A always gives exactly one value of B | StudentID determines StudentName |
| Partial-key dependency | A non-key attribute depends on only part of a composite key | With key (PurchaseID, ItemName), UnitPrice depends on ItemName alone |
| Non-key or transitive dependency | A non-key attribute depends on another non-key attribute rather than on the key | SupplierPhone depends on SupplierName, not on ItemID |
| Multi-valued dependency | One key value determines a set of several independent values, and two such independent sets in one table force every combination to be stored | One student's list of clubs and, separately, their list of allergies |
- Partial and transitive dependencies are regularly swapped in answers, and the difference is where the attribute points.
- Partial means it depends on part of the key, so it can only happen where the key is composite.
- Transitive means it depends on a column that is not in the key at all, so it can happen with a single-column key.
- A multi-valued dependency is a separate problem again: the two lists are independent of each other, so storing them together multiplies the rows without adding information.
- Every attribute must hold a single atomic value, so lists and repeated columns are not allowed.
- Every table must have a key that gives unique identification of its rows.
- Repeating data is moved out into a new entity, while the non-repeating data stays where it is and is given a primary key.
- The primary key of the original entity is added to the new entity as a foreign key, and the new entity is normally identified by a composite key.
- Reaching 1NF usually creates a composite key, and a composite key is exactly what makes partial-key dependencies possible.
- That is why 2NF follows 1NF rather than standing on its own.
- A table is in 2NF when it is in 1NF and every non-key attribute depends on the whole primary key.
- Each attribute that depends on only part of a composite key is moved into its own entity.
- That new entity is given a primary key, and the original entity keeps that key as a foreign key.
- A table whose primary key is a single column is automatically in 2NF, because a single column has no parts.
- After 2NF, the problem still left is a non-key attribute that depends on another non-key attribute.
- That attribute is not tied to the key at all, so it can be duplicated and go stale exactly like the data 1NF removed.
- A table is in 3NF when it is in 2NF and no non-key attribute depends on another non-key attribute.
- Each transitive dependency is moved into a separate entity with its own primary key.
- That new primary key becomes a foreign key in the entity the attributes were removed from.
- Transitive dependencies can appear in any entity created at an earlier stage, so every table has to be checked and not only the last one you made.
- The three forms fit into one sentence: every non-key attribute must depend on the key, the whole key, and nothing but the key.
- "The key" is 1NF, because there has to be a key at all and the values have to be atomic.
- "The whole key" is 2NF, which rules out partial-key dependencies.
- "Nothing but the key" is 3NF, which rules out transitive dependencies.
| Form | Condition added | Problem it removes | Action taken |
|---|
| 1NF | Atomic values and a key that uniquely identifies each row | Repeating groups and multi-valued cells | Move the repeating data into a new entity linked by a foreign key |
| 2NF | Every non-key attribute depends on the whole key | Partial-key dependencies | Move the partially dependent attributes into their own entity |
| 3NF | No non-key attribute depends on another non-key attribute | Transitive or non-key dependencies | Move the dependent group into a new entity and link it with a foreign key |
- A3.2.5 uses the command term Explain, so a difference between two forms needs the reason attached to it.
- Name the dependency each form removes and then name the anomaly that removal prevents.
- Where a scenario is given, quote its own column names back, because an answer about "the table" and "the attribute" fits any scenario and earns less.
The shop currently keeps one spreadsheet row per receipt, so a receipt with two items holds two values in several cells.
| StudentID | StudentName | PurchaseDate | PaymentMethod | ItemsPurchased | UnitPrices | SupplierName | SupplierPhone |
|---|
| 101 | Alice Smith | 2024-05-10 | Card | Pen, Notebook | 2.00, 6.00 | Stationery Co, Stationery Co | 020 7946 0011, 020 7946 0011 |
| 102 | Ben Wong | 2024-05-11 | Cash | Pencil | 1.50 | Stationery Co | 020 7946 0011 |
| 101 | Alice Smith | 2024-05-12 | Card | Ruler | 2.00 | Precision Tools | 020 7946 0198 |
Split the multi-valued cells so that each row describes one item on one receipt.
| StudentID | StudentName | PurchaseDate | PaymentMethod | ItemName | UnitPrice | SupplierName | SupplierPhone |
|---|
| 101 | Alice Smith | 2024-05-10 | Card | Pen | 2.00 | Stationery Co | 020 7946 0011 |
| 101 | Alice Smith | 2024-05-10 | Card | Notebook | 6.00 | Stationery Co | 020 7946 0011 |
| 102 | Ben Wong | 2024-05-11 | Cash | Pencil | 1.50 | Stationery Co | 020 7946 0011 |
| 101 | Alice Smith | 2024-05-12 | Card | Ruler | 2.00 | Precision Tools | 020 7946 0198 |
StudentName repeats on every row for the same student, so it moves into its own entity.
Student (PK StudentID)
| StudentID | StudentName |
|---|
| 101 | Alice Smith |
| 102 | Ben Wong |
Purchase (PK StudentID + PurchaseDate + ItemName, FK StudentID)
| StudentID | PurchaseDate | ItemName | PaymentMethod | UnitPrice | SupplierName | SupplierPhone |
|---|
| 101 | 2024-05-10 | Pen | Card | 2.00 | Stationery Co | 020 7946 0011 |
| 101 | 2024-05-10 | Notebook | Card | 6.00 | Stationery Co | 020 7946 0011 |
| 102 | 2024-05-11 | Pencil | Cash | 1.50 | Stationery Co | 020 7946 0011 |
| 101 | 2024-05-12 | Ruler | Card | 2.00 | Precision Tools | 020 7946 0198 |
- The table is now in 1NF, and the composite key has exposed two partial-key dependencies.
- PaymentMethod depends on StudentID and PurchaseDate together, but not on ItemName.
- UnitPrice, SupplierName and SupplierPhone depend on ItemName alone.
The receipt-level data becomes its own entity with a surrogate key, PurchaseID.
Purchase (PK PurchaseID, FK StudentID)
| PurchaseID | StudentID | PurchaseDate | PaymentMethod |
|---|
| 1 | 101 | 2024-05-10 | Card |
| 2 | 102 | 2024-05-11 | Cash |
| 3 | 101 | 2024-05-12 | Card |
The item-level data becomes an Item entity with its own key.
Item (PK ItemID)
| ItemID | ItemName | UnitPrice | SupplierName | SupplierPhone |
|---|
| 1 | Pen | 2.00 | Stationery Co | 020 7946 0011 |
| 2 | Notebook | 6.00 | Stationery Co | 020 7946 0011 |
| 3 | Pencil | 1.50 | Stationery Co | 020 7946 0011 |
| 4 | Ruler | 2.00 | Precision Tools | 020 7946 0198 |
What is left is the line items, which link a purchase to an item.
PurchaseLine (PK PurchaseID + ItemID, FK PurchaseID, FK ItemID)
| PurchaseID | ItemID | Quantity |
|---|
| 1 | 1 | 1 |
| 1 | 2 | 1 |
| 2 | 3 | 1 |
| 3 | 4 | 1 |
- All four tables are now in 2NF, but the Item table still holds a transitive dependency.
- SupplierPhone depends on SupplierName, and SupplierName is not the key of Item.
- The consequence is visible in the data: the Stationery Co number is stored three times, so a change of number means three edits.
The supplier attributes move into a Supplier entity, and Item keeps only a foreign key to it.
Supplier (PK SupplierID)
| SupplierID | SupplierName | SupplierPhone |
|---|
| 1 | Stationery Co | 020 7946 0011 |
| 2 | Precision Tools | 020 7946 0198 |
Item (PK ItemID, FK SupplierID)
| ItemID | ItemName | UnitPrice | SupplierID |
|---|
| 1 | Pen | 2.00 | 1 |
| 2 | Notebook | 6.00 | 1 |
| 3 | Pencil | 1.50 | 1 |
| 4 | Ruler | 2.00 | 2 |
The finished design has five tables: Student, Purchase, PurchaseLine, Item and Supplier.
- Check the result against the three anomalies to see what has been bought.
- Update: a supplier's phone number is stored once, so it is changed in one place.
- Insert: a new item can be priced in the Item table before anybody buys it.
- Delete: deleting Ben Wong's purchase removes the sale and leaves the pencil's price intact.
- Data duplication
- Each stage moves a repeated fact into a table where it is stored once and referenced by a key.
- Missing data
- Giving each fact its own table means a fact can be recorded as soon as it is known, instead of waiting for an unrelated row to exist.
- Dependency concerns
- Composite key dependencies are resolved at 2NF by removing partial-key dependencies.
- Transitive dependencies are resolved at 3NF by giving the dependent group its own entity.
- Multi-valued dependencies are resolved by putting each independent list in its own table, so a student's clubs and their allergies never share a row.
- State the condition each of 1NF, 2NF and 3NF adds.
- Explain the difference between a partial-key dependency and a transitive dependency.
- Why is a table with a single-column primary key automatically in 2NF?
- Name the three anomalies and give one example of each.
- A table has key ClassID and holds TeacherID and TeacherEmail. Which normal form does it break, and what would you do about it?