Normalisation
Databases
Important Notice
Contents
What is Normalisation?
Imagine a spreadsheet where one cell contains multiple values separated by slashes — like storing several item numbers, descriptions and prices all in a single row. That is an unnormalised table, and it makes updating, searching and maintaining data a nightmare. Normalisation is the step-by-step process of reorganising that messy table into a set of well-structured tables that eliminate redundancy and protect data integrity.
The process follows a series of normal forms, each building on the previous one. First Normal Form (1NF) ensures every cell holds a single, atomic value — no repeating groups. Second Normal Form (2NF) removes partial dependencies, where a non-key attribute depends on only part of a composite key. Third Normal Form (3NF) removes transitive dependencies, where a non-key attribute depends on another non-key attribute rather than the primary key.
Think of it like organising a messy filing cabinet: 1NF makes sure each drawer has one type of document, 2NF ensures documents are filed under the right category, and 3NF moves cross-referenced information to its own dedicated drawer. By the end, each piece of data lives in exactly one place — update it once and it is correct everywhere.
In this lesson, we will walk through two complete examples — a computer hardware order system and a hospital visit system — transforming each from a single chaotic table into a clean set of normalised tables in 3NF. Along the way, you will learn to identify primary keys, foreign keys, composite keys, and the dependencies that drive each normalisation step.
UNF to 1NF — Removing Repeating Groups
Hardware order example: one value per cell, one fact per row
How to spot it: Look at each cell in your table. Does any cell contain more than one value (separated by commas, slashes, or listed vertically)? If yes, those attributes form a repeating group. The fix is always the same: move the repeating attributes into a new table, give it a meaningful name, and link back using the original primary key as a foreign key.
| Order No | Date | Cust No | Name | Item No | Description | Cost | Qty |
|---|---|---|---|---|---|---|---|
| 1001 | 05-Feb | 0123 | Amal | X3412/X2189 | 120Gb HD/Cisco NIC | 40/20 | 5/25 |
| 1002 | 10-Feb | 0345 | Ali | Y7674/B3456/F67584 | 17" Monitor/Wireless Mouse/2GB Ram | 50/10/80 | 6/10/7 |
| Order No | Date | Cust No | Name | Address | Contact | Item No | Description | Cost | Qty |
|---|---|---|---|---|---|---|---|---|---|
| 1001 | 05-Feb | 0123 | Amal | Dublin | 39112200 | X3412 | 120Gb HD | 40 | 5 |
| 1001 | 05-Feb | 0123 | Amal | Dublin | 39112200 | X2189 | Cisco NIC | 20 | 25 |
| 1002 | 10-Feb | 0345 | Ali | Meath | 3321001 | Y7674 | 17" Monitor | 50 | 6 |
| 1002 | 10-Feb | 0345 | Ali | Meath | 3321001 | B3456 | Wireless Mouse | 10 | 10 |
| 1002 | 10-Feb | 0345 | Ali | Meath | 3321001 | F67584 | 2GB Ram | 80 | 7 |
| Order No (PK) | Date | Cust No | Name | Address | Contact |
|---|---|---|---|---|---|
| 1001 | 05-Feb-2024 | 0123 | Amal | Dublin | 39112200 |
| 1002 | 10-Feb-2024 | 0345 | Ali | Meath | 3321001 |
| Order No (FK) | Item No (PK) | Description | Cost | Qty |
|---|---|---|---|---|
| 1001 | X3412 | 120Gb HD | 40 | 5 |
| 1001 | X2189 | Cisco NIC | 20 | 25 |
| 1002 | Y7674 | 17" Monitor | 50 | 6 |
| 1002 | B3456 | Wireless Mouse | 10 | 10 |
| 1002 | F67584 | 2GB Ram | 80 | 7 |
The repeating item columns (orange) move to their own table. Each item now has its own row, and the two tables are linked by Order Number.
1NF to 2NF — Removing Partial Dependencies
Hardware order example: Description and Unit Cost depend only on Item Number
How to spot it: First, check if any table has a composite key (two or more columns forming the primary key). If it does, ask yourself for each non-key attribute: "Does this attribute need BOTH parts of the key to be identified, or just one?" If the answer is "just one", that attribute has a partial dependency and must move to its own table. Here, "What is item X3412 called?" only needs Item Number — it does not matter which order it belongs to.
| Order No (FK) | Item No (FK) | Qty |
|---|---|---|
| 1001 | X3412 | 5 |
| 1001 | X2189 | 25 |
| 1002 | Y7674 | 6 |
| 1002 | B3456 | 10 |
| 1002 | F67584 | 7 |
| Item No (PK) | Description | Unit Cost |
|---|---|---|
| X3412 | 120Gb HD | 40 |
| X2189 | Cisco NIC | 20 |
| Y7674 | 17" Monitor | 50 |
| B3456 | Wireless Mouse | 10 |
| F67584 | 2GB Ram | 80 |
Description and Unit Cost move to ITEM because they depend only on Item Number, not on the full composite key.
2NF to 3NF — Removing Transitive Dependencies
Hardware order example: Name, Address and Contact depend on Customer Number, not Order Number
How to spot it: For each non-key attribute, ask: "Does this attribute describe the primary key directly, or does it describe another non-key attribute?" If Name describes Customer Number (not Order Number), you have a transitive dependency. The practical test: "If I change this value, would it be wrong in other rows?" If Amal moves from Dublin to Cork, every order she placed would show the wrong address — that means address belongs in its own table.
| Order No (PK) | Cust No (FK) | Order Date |
|---|---|---|
| 1001 | 0123 | 05-Feb-2024 |
| 1002 | 0345 | 10-Feb-2024 |
| Cust No (PK) | Name | Address | Contact |
|---|---|---|---|
| 0123 | Amal | Dublin | 39112200 |
| 0345 | Ali | Meath | 3321001 |
| Order No (PK) | Cust No (FK) | Date |
|---|---|---|
| 1001 | 0123 | 05-Feb-2024 |
| 1002 | 0345 | 10-Feb-2024 |
| Cust No (PK) | Name | Address | Contact |
|---|---|---|---|
| 0123 | Amal | Dublin | 39112200 |
| 0345 | Ali | Meath | 3321001 |
| Item No (PK) | Description | Cost |
|---|---|---|
| X3412 | 120Gb HD | 40 |
| X2189 | Cisco NIC | 20 |
| Y7674 | 17" Monitor | 50 |
| B3456 | Wireless Mouse | 10 |
| F67584 | 2GB Ram | 80 |
| Order No (FK) | Item No (FK) | Qty |
|---|---|---|
| 1001 | X3412 | 5 |
| 1001 | X2189 | 25 |
| 1002 | Y7674 | 6 |
| 1002 | B3456 | 10 |
| 1002 | F67584 | 7 |
The complete 3NF result: ORDER, CUSTOMER, ITEM, and ORDER_ITEM — four tables with no redundancy, no partial dependencies, and no transitive dependencies.
Hardware Order — Table Relationships
How the four 3NF tables connect through foreign keys
Hospital Visit System — Step by Step
Applying the three-step checklist to healthcare data
| VisitID | Patient | Date | Treatments |
|---|---|---|---|
| V101 | Ali Khan | 2026-03-10 | X-Ray (Dr Smith, Radiology, €120), Blood Test (Dr John, Pathology, €50) |
| V102 | Sara Noor | 2026-03-11 | MRI Scan (Dr Lee, Imaging, €300), ECG (Dr Patel, Cardiology, €90) |
| V103 | Emma Cole | 2026-03-12 | Consultation (Dr Patel, Cardiology, €80), X-Ray (Dr Smith, Radiology, €120) |
| VisitID | PatientID | PatientName | Date | Treatment | Doctor | Dept | Cost |
|---|---|---|---|---|---|---|---|
| V101 | P01 | Ali Khan | 2026-03-10 | X-Ray | Dr Smith | Radiology | €120 |
| V101 | P01 | Ali Khan | 2026-03-10 | Blood Test | Dr John | Pathology | €50 |
| V102 | P02 | Sara Noor | 2026-03-11 | MRI Scan | Dr Lee | Imaging | €300 |
| V102 | P02 | Sara Noor | 2026-03-11 | ECG | Dr Patel | Cardiology | €90 |
| V103 | P03 | Emma Cole | 2026-03-12 | Consultation | Dr Patel | Cardiology | €80 |
| V103 | P03 | Emma Cole | 2026-03-12 | X-Ray | Dr Smith | Radiology | €120 |
| VisitID | PatientID | Name | Date |
|---|---|---|---|
| V101 | P01 | Ali Khan | 2026-03-10 |
| V102 | P02 | Sara Noor | 2026-03-11 |
| V103 | P03 | Emma Cole | 2026-03-12 |
| VisitID (FK) | Treatment | Doctor | Dept | Cost |
|---|---|---|---|---|
| V101 | X-Ray | Dr Smith | Radiology | €120 |
| V101 | Blood Test | Dr John | Pathology | €50 |
| V102 | MRI Scan | Dr Lee | Imaging | €300 |
| V102 | ECG | Dr Patel | Cardiology | €90 |
| V103 | Consultation | Dr Patel | Cardiology | €80 |
| V103 | X-Ray | Dr Smith | Radiology | €120 |
| PatientID | Name |
|---|---|
| P01 | Ali Khan |
| P02 | Sara Noor |
| P03 | Emma Cole |
| VisitID | PatientID (FK) | Date |
|---|---|---|
| V101 | P01 | 2026-03-10 |
| V102 | P02 | 2026-03-11 |
| V103 | P03 | 2026-03-12 |
| DoctorID | Name | Dept |
|---|---|---|
| D01 | Dr Smith | Radiology |
| D02 | Dr John | Pathology |
| D03 | Dr Lee | Imaging |
| D04 | Dr Patel | Cardiology |
| TreatmentID | Name | Cost |
|---|---|---|
| T01 | X-Ray | €120 |
| T02 | Blood Test | €50 |
| T03 | MRI Scan | €300 |
| T04 | ECG | €90 |
| T05 | Consultation | €80 |
| VisitID (FK) | TreatmentID (FK) | DoctorID (FK) |
|---|---|---|
| V101 | T01 | D01 |
| V101 | T02 | D02 |
| V102 | T03 | D03 |
| V102 | T04 | D04 |
| V103 | T05 | D04 |
| V103 | T01 | D01 |
The hospital example produces five tables in 3NF. Each fact is stored once — updating a doctor's department or a treatment's cost requires changing only one row.
Hospital Visit System — Table Relationships
How the five 3NF tables connect through foreign keys
How to Identify Where to Split Tables
A three-step decision checklist for each normal form
Look for: Slashes (X3412/X2189), comma-separated lists, multiple rows of data packed into one cell.
If YES: First, expand every multi-valued cell into its own row — you get one big flat table where every cell is atomic. Then notice the redundancy (data repeating across rows) and split the repeating attributes into a new table. Use the original PK as a foreign key in the new table and create a composite key (original PK + new attribute PK).
If NO: The table is already in 1NF — proceed to step 2.
Test: For each non-key column, ask: "Do I need BOTH parts of the composite key to look up this value?"
If YES (partial dep exists): Move the partially dependent attributes to a new table, keyed by the part they depend on.
If NO (or no composite key): The table is already in 2NF — proceed to step 3.
Test: For each non-key column, ask: "Does this describe the PK directly, or does it describe a different column?"
Practical test: "If I update this value, would other rows become inconsistent?"
If YES (transitive dep exists): Move the transitively dependent attributes to a new table. Keep the intermediary column as a FK.
If NO: Congratulations — your table is in 3NF!
Apply these three checks in order to any table. Each step builds on the previous one — you must achieve 1NF before checking for 2NF, and 2NF before checking for 3NF.
Worked Example — Lecturer Course System
Normalising a college timetable from UNF to 3NF
| Lect No | Name | Faculty | Office | Course Code | Course Name | Start Date | Weekly Hrs |
|---|---|---|---|---|---|---|---|
| 7146 | James | Business | Room 22 | BM01 | Buss Manage | 12/9/2023 | 4 |
| A01 | Account | 11/9/2023 | 3 | ||||
| E01 | Economics | 30/9/2023 | 7 | ||||
| 1463 | Denis | IT | Room 21 | CS01 | Computer Systems | 01/9/2023 | 6 |
| P01 | Programming | 02/9/2023 | 5 | ||||
| 6455 | Phil | Business | Room 22 | BM01 | Buss Manage | 04/10/2023 | 4 |
| M01 | Marketing | 10/10/2023 | 6 |
| Lect No | Name | Faculty | Office | Course Code | Course Name | Start | Hrs |
|---|---|---|---|---|---|---|---|
| 7146 | James | Business | Room 22 | BM01 | Buss Manage | 12/9/23 | 4 |
| 7146 | James | Business | Room 22 | A01 | Account | 11/9/23 | 3 |
| 7146 | James | Business | Room 22 | E01 | Economics | 30/9/23 | 7 |
| 1463 | Denis | IT | Room 21 | CS01 | Comp Systems | 01/9/23 | 6 |
| 1463 | Denis | IT | Room 21 | P01 | Programming | 02/9/23 | 5 |
| 6455 | Phil | Business | Room 22 | BM01 | Buss Manage | 04/10/23 | 4 |
| 6455 | Phil | Business | Room 22 | M01 | Marketing | 10/10/23 | 6 |
| Lect No (PK) | Name | Faculty | Office |
|---|---|---|---|
| 7146 | James | Business | Room 22 |
| 1463 | Denis | IT | Room 21 |
| 6455 | Phil | Business | Room 22 |
| Lect No (FK) | Course Code | Course Name | Start | Hrs |
|---|---|---|---|---|
| 7146 | BM01 | Buss Manage | 12/9/23 | 4 |
| 7146 | A01 | Account | 11/9/23 | 3 |
| 7146 | E01 | Economics | 30/9/23 | 7 |
| 1463 | CS01 | Comp Systems | 01/9/23 | 6 |
| 1463 | P01 | Programming | 02/9/23 | 5 |
| 6455 | BM01 | Buss Manage | 04/10/23 | 4 |
| 6455 | M01 | Marketing | 10/10/23 | 6 |
| Code (PK) | Name |
|---|---|
| BM01 | Buss Manage |
| A01 | Account |
| E01 | Economics |
| CS01 | Comp Systems |
| P01 | Programming |
| M01 | Marketing |
| Lect No (FK) | Code (FK) | Start Date | Weekly Hrs |
|---|---|---|---|
| 7146 | BM01 | 12/9/23 | 4 |
| 7146 | A01 | 11/9/23 | 3 |
| 7146 | E01 | 30/9/23 | 7 |
| 1463 | CS01 | 01/9/23 | 6 |
| 1463 | P01 | 02/9/23 | 5 |
| 6455 | BM01 | 04/10/23 | 4 |
| 6455 | M01 | 10/10/23 | 6 |
| Lect No (PK) | Name | Faculty | Office |
|---|---|---|---|
| 7146 | James | Business | Room 22 |
| 1463 | Denis | IT | Room 21 |
| 6455 | Phil | Business | Room 22 |
| Code (PK) | Name |
|---|---|
| BM01 | Buss Manage |
| A01 | Account |
| E01 | Economics |
| CS01 | Comp Systems |
| P01 | Programming |
| M01 | Marketing |
| Lect No (FK) | Code (FK) | Start | Hrs |
|---|---|---|---|
| 7146 | BM01 | 12/9/23 | 4 |
| 7146 | A01 | 11/9/23 | 3 |
| 7146 | E01 | 30/9/23 | 7 |
| 1463 | CS01 | 01/9/23 | 6 |
| 1463 | P01 | 02/9/23 | 5 |
| 6455 | BM01 | 04/10/23 | 4 |
| 6455 | M01 | 10/10/23 | 6 |
The lecturer example uses the same three-step checklist. Course Name had a partial dependency on Course Code, but no transitive dependency was found — 3NF was reached in step 2.
Lecturer Course System — Table Relationships
How the three 3NF tables connect through foreign keys
SQL — Step 1: UNF to 1NF
Split the single ORDER table into ORDER + ORDER_ITEM
-- STEP 1: UNF → 1NF -- Remove repeating groups (item details) into a new table CREATE TABLE "Order" ( order_number INT PRIMARY KEY, order_date DATE NOT NULL, customer_number VARCHAR(4) NOT NULL, name VARCHAR(50) NOT NULL, address VARCHAR(100) NOT NULL, contact_number VARCHAR(20) NOT NULL ); -- New table for the repeating item group -- Composite key: order_number + item_number CREATE TABLE Order_Item ( order_number INT REFERENCES "Order", item_number VARCHAR(10) NOT NULL, description VARCHAR(100) NOT NULL, unit_cost DECIMAL(10,2) NOT NULL, quantity INT NOT NULL, PRIMARY KEY (order_number, item_number) );
SQL — Step 2: 1NF to 2NF
Extract ITEM table to remove partial dependency
-- STEP 2: 1NF → 2NF -- Description and unit_cost depend only on item_number -- (partial dependency on the composite key) -- Move them to a new ITEM table CREATE TABLE Item ( item_number VARCHAR(10) PRIMARY KEY, description VARCHAR(100) NOT NULL, unit_cost DECIMAL(10,2) NOT NULL ); -- Order_Item now only keeps quantity -- (depends on the FULL composite key) CREATE TABLE Order_Item ( order_number INT REFERENCES "Order", item_number VARCHAR(10) REFERENCES Item, quantity INT NOT NULL, PRIMARY KEY (order_number, item_number) );
SQL — Step 3: 2NF to 3NF
Extract CUSTOMER table to remove transitive dependency
-- STEP 3: 2NF → 3NF -- Name, address and contact depend on customer_number -- (transitive dependency — not on the PK) -- Move them to a new CUSTOMER table CREATE TABLE Customer ( customer_number VARCHAR(4) PRIMARY KEY, name VARCHAR(50) NOT NULL, address VARCHAR(100) NOT NULL, contact_number VARCHAR(20) NOT NULL ); -- Order now only keeps customer_number as FK CREATE TABLE "Order" ( order_number INT PRIMARY KEY, customer_number VARCHAR(4) REFERENCES Customer, order_date DATE NOT NULL ); -- Final schema: 4 tables in 3NF -- Customer, Order, Item, Order_Item -- Each fact stored exactly once ✓
Quick Reference
| Concept | Rule | What to Do |
|---|---|---|
| UNF | Raw data, may have repeating groups | Identify entity, list all attributes, find the key |
| 1NF | No multi-valued attributes | Remove repeating groups into a new table; add a foreign key to link them |
| 2NF | No partial dependencies | If a composite key exists, move attributes that depend on only part of it |
| 3NF | No transitive dependencies | Move non-key attributes that depend on other non-key attributes |
| Primary Key (PK) | Uniquely identifies each row | Cannot be NULL; underlined in notation |
| Foreign Key (FK) | References a PK in another table | Creates relationships between tables |
| Composite Key | Two or more attributes forming a PK | Used when no single attribute is unique (e.g. Order No + Item No) |
Practice Exercises
Test your understanding of normalisation
Lecturer_no, Name, Faculty, Office_loc, Course_code, Course_name, Start_date, Weekly_time. One lecturer teaches multiple courses. What are the repeating (multi-valued) attributes?| LoanID | MemberName | MemberEmail | BookTitle | Author | LoanDate | ReturnDate |
|---|---|---|---|---|---|---|
| L01 | Jane Doe | jane@mail.com | SQL Basics | T. Brown | 01/03/26 | 15/03/26 |
| L02 | Jane Doe | jane@mail.com | Data Design | R. Singh | 05/03/26 | 19/03/26 |
| L03 | Mark Lee | mark@mail.com | SQL Basics | T. Brown | 10/03/26 | 24/03/26 |
| BookingID | Client | Phone | Class | Instructor | Inst Phone | Room | Date |
|---|---|---|---|---|---|---|---|
| B01 | Anna | 555-1234 | Yoga | Coach Kim | 555-9999 | R1 | 10/03/26 |
| B02 | Tom | 555-5678 | Yoga | Coach Kim | 555-9999 | R1 | 10/03/26 |
| B03 | Anna | 555-1234 | Pilates | Coach Lee | 555-8888 | R2 | 11/03/26 |
| PurchID | CustEmail | CustName | Product | Category | CatDiscount | Qty | Date |
|---|---|---|---|---|---|---|---|
| P01 | jo@mail.com | Jo | Keyboard | Peripherals | 10% | 2 | 01/03/26 |
| P02 | jo@mail.com | Jo | Monitor | Displays | 5% | 1 | 02/03/26 |
| P03 | sam@mail.com | Sam | Mouse | Peripherals | 10% | 3 | 03/03/26 |
| ReservID | Guest | GuestEmail | CheckIn | RoomNo | RoomType | Rate | Services |
|---|---|---|---|---|---|---|---|
| R01 | Liam | liam@mail.com | 01/03 | 101 | Single | €80 | Breakfast €15, Spa €40 |
| R02 | Mia | mia@mail.com | 02/03 | 205 | Double | €120 | Breakfast €15, Gym €10, Laundry €25 |
| R03 | Liam | liam@mail.com | 10/03 | 101 | Single | €80 | Gym €10 |
| StudentID | Name | Address | DeptCode | DeptName | Modules |
|---|---|---|---|---|---|
| S001 | Ava | Dublin | CS | Comp Sci | M101 Databases (Dr Ryan, B+), M102 Networks (Dr Kelly, A) |
| S002 | Noah | Cork | CS | Comp Sci | M101 Databases (Dr Ryan, A-), M103 Web Dev (Dr Murphy, B) |
| S003 | Ella | Galway | BA | Business | M201 Marketing (Dr Walsh, A), M101 Databases (Dr Ryan, B+) |
Answers
| LoanID | MemberName | MemberEmail | BookTitle | Author | LoanDate | ReturnDate |
|---|---|---|---|---|---|---|
| L01 | Jane Doe | jane@mail.com | SQL Basics | T. Brown | 01/03/26 | 15/03/26 |
| L02 | Jane Doe | jane@mail.com | Data Design | R. Singh | 05/03/26 | 19/03/26 |
| L03 | Mark Lee | mark@mail.com | SQL Basics | T. Brown | 10/03/26 | 24/03/26 |
| LoanID | MemberName | MemberEmail | BookTitle | Author | LoanDate | ReturnDate |
|---|---|---|---|---|---|---|
| L01 | Jane Doe | jane@mail.com | SQL Basics | T. Brown | 01/03/26 | 15/03/26 |
| L02 | Jane Doe | jane@mail.com | Data Design | R. Singh | 05/03/26 | 19/03/26 |
| L03 | Mark Lee | mark@mail.com | SQL Basics | T. Brown | 10/03/26 | 24/03/26 |
| LoanID | MemberName | MemberEmail | BookTitle | Author | LoanDate | ReturnDate |
|---|---|---|---|---|---|---|
| L01 | Jane Doe | jane@mail.com | SQL Basics | T. Brown | 01/03/26 | 15/03/26 |
| L02 | Jane Doe | jane@mail.com | Data Design | R. Singh | 05/03/26 | 19/03/26 |
| L03 | Mark Lee | mark@mail.com | SQL Basics | T. Brown | 10/03/26 | 24/03/26 |
• MemberName & MemberEmail depend on the member, not on LoanID — transitive dependency.
• BookTitle & Author depend on the book, not on LoanID — transitive dependency.
Fix: extract MEMBER and BOOK tables.
| MemberID | MemberName | MemberEmail |
|---|---|---|
| M01 | Jane Doe | jane@mail.com |
| M02 | Mark Lee | mark@mail.com |
| BookID | BookTitle | Author |
|---|---|---|
| B01 | SQL Basics | T. Brown |
| B02 | Data Design | R. Singh |
| LoanID | MemberID (FK) | BookID (FK) | LoanDate | ReturnDate |
|---|---|---|---|---|
| L01 | M01 | B01 | 01/03/26 | 15/03/26 |
| L02 | M01 | B02 | 05/03/26 | 19/03/26 |
| L03 | M02 | B01 | 10/03/26 | 24/03/26 |
| BookingID | Client | Phone | Class | Instructor | Inst Phone | Room | Date |
|---|---|---|---|---|---|---|---|
| B01 | Anna | 555-1234 | Yoga | Coach Kim | 555-9999 | R1 | 10/03/26 |
| B02 | Tom | 555-5678 | Yoga | Coach Kim | 555-9999 | R1 | 10/03/26 |
| B03 | Anna | 555-1234 | Pilates | Coach Lee | 555-8888 | R2 | 11/03/26 |
| BookingID | Client | Phone | Class | Instructor | Inst Phone | Room | Date |
|---|---|---|---|---|---|---|---|
| B01 | Anna | 555-1234 | Yoga | Coach Kim | 555-9999 | R1 | 10/03/26 |
| B02 | Tom | 555-5678 | Yoga | Coach Kim | 555-9999 | R1 | 10/03/26 |
| B03 | Anna | 555-1234 | Pilates | Coach Lee | 555-8888 | R2 | 11/03/26 |
| BookingID | Client | Phone | Class | Instructor | Inst Phone | Room | Date |
|---|---|---|---|---|---|---|---|
| B01 | Anna | 555-1234 | Yoga | Coach Kim | 555-9999 | R1 | 10/03/26 |
| B02 | Tom | 555-5678 | Yoga | Coach Kim | 555-9999 | R1 | 10/03/26 |
| B03 | Anna | 555-1234 | Pilates | Coach Lee | 555-8888 | R2 | 11/03/26 |
• Phone depends on Client, not on BookingID — transitive dependency (Anna's phone repeats in B01 & B03).
• Instructor, Inst Phone & Room depend on Class, not on BookingID — transitive dependency (Yoga is always Coach Kim in R1).
• Inst Phone depends on Instructor, not on Class — another transitive dependency (Coach Kim's phone describes the instructor).
Fix: extract CLIENT, INSTRUCTOR, and CLASS tables.
| ClientID | ClientName | Phone |
|---|---|---|
| C01 | Anna | 555-1234 |
| C02 | Tom | 555-5678 |
| InstructorID | Name | Phone |
|---|---|---|
| I01 | Coach Kim | 555-9999 |
| I02 | Coach Lee | 555-8888 |
| ClassID | ClassName | InstructorID (FK) | Room |
|---|---|---|---|
| CL01 | Yoga | I01 | R1 |
| CL02 | Pilates | I02 | R2 |
| BookingID | ClientID (FK) | ClassID (FK) | Date |
|---|---|---|---|
| B01 | C01 | CL01 | 10/03/26 |
| B02 | C02 | CL01 | 10/03/26 |
| B03 | C01 | CL02 | 11/03/26 |
| PurchID | CustEmail | CustName | Product | Category | CatDiscount | Qty | Date |
|---|---|---|---|---|---|---|---|
| P01 | jo@mail.com | Jo | Keyboard | Peripherals | 10% | 2 | 01/03/26 |
| P02 | jo@mail.com | Jo | Monitor | Displays | 5% | 1 | 02/03/26 |
| P03 | sam@mail.com | Sam | Mouse | Peripherals | 10% | 3 | 03/03/26 |
| PurchID | CustEmail | CustName | Product | Category | CatDiscount | Qty | Date |
|---|---|---|---|---|---|---|---|
| P01 | jo@mail.com | Jo | Keyboard | Peripherals | 10% | 2 | 01/03/26 |
| P02 | jo@mail.com | Jo | Monitor | Displays | 5% | 1 | 02/03/26 |
| P03 | sam@mail.com | Sam | Mouse | Peripherals | 10% | 3 | 03/03/26 |
| PurchID | CustEmail | CustName | Product | Category | CatDiscount | Qty | Date |
|---|---|---|---|---|---|---|---|
| P01 | jo@mail.com | Jo | Keyboard | Peripherals | 10% | 2 | 01/03/26 |
| P02 | jo@mail.com | Jo | Monitor | Displays | 5% | 1 | 02/03/26 |
| P03 | sam@mail.com | Sam | Mouse | Peripherals | 10% | 3 | 03/03/26 |
• CustName depends on CustEmail, not on PurchID — transitive dependency (Jo's name repeats whenever jo@mail.com appears).
• Category depends on Product, not on PurchID — transitive dependency (Keyboard is always Peripherals).
• CatDiscount depends on Category, not on Product — this is a double transitive chain: PurchID → Product → Category → CatDiscount (10% belongs to all Peripherals, not per product).
Fix: extract CUSTOMER, CATEGORY, and PRODUCT tables.
| CustID | CustEmail | CustName |
|---|---|---|
| C01 | jo@mail.com | Jo |
| C02 | sam@mail.com | Sam |
| CatID | CatName | CatDiscount |
|---|---|---|
| CAT01 | Peripherals | 10% |
| CAT02 | Displays | 5% |
| ProdID | ProdName | CatID (FK) |
|---|---|---|
| PR01 | Keyboard | CAT01 |
| PR02 | Monitor | CAT02 |
| PR03 | Mouse | CAT01 |
| PurchID | CustID (FK) | ProdID (FK) | Qty | Date |
|---|---|---|---|---|
| P01 | C01 | PR01 | 2 | 01/03/26 |
| P02 | C01 | PR02 | 1 | 02/03/26 |
| P03 | C02 | PR03 | 3 | 03/03/26 |
| ReservID | Guest | GuestEmail | CheckIn | RoomNo | RoomType | Rate | Services |
|---|---|---|---|---|---|---|---|
| R01 | Liam | liam@mail.com | 01/03 | 101 | Single | €80 | Breakfast €15, Spa €40 |
| R02 | Mia | mia@mail.com | 02/03 | 205 | Double | €120 | Breakfast €15, Gym €10, Laundry €25 |
| R03 | Liam | liam@mail.com | 10/03 | 101 | Single | €80 | Gym €10 |
| ReservID | Guest | GuestEmail | CheckIn | RoomNo | RoomType | Rate | ServiceName | ServicePrice |
|---|---|---|---|---|---|---|---|---|
| R01 | Liam | liam@mail.com | 01/03 | 101 | Single | €80 | Breakfast | €15 |
| R01 | Liam | liam@mail.com | 01/03 | 101 | Single | €80 | Spa | €40 |
| R02 | Mia | mia@mail.com | 02/03 | 205 | Double | €120 | Breakfast | €15 |
| R02 | Mia | mia@mail.com | 02/03 | 205 | Double | €120 | Gym | €10 |
| R02 | Mia | mia@mail.com | 02/03 | 205 | Double | €120 | Laundry | €25 |
| R03 | Liam | liam@mail.com | 10/03 | 101 | Single | €80 | Gym | €10 |
| ReservID | Guest | GuestEmail | CheckIn | RoomNo | RoomType | Rate |
|---|---|---|---|---|---|---|
| R01 | Liam | liam@mail.com | 01/03 | 101 | Single | €80 |
| R02 | Mia | mia@mail.com | 02/03 | 205 | Double | €120 |
| R03 | Liam | liam@mail.com | 10/03 | 101 | Single | €80 |
| ReservID | ServiceName | Price |
|---|---|---|
| R01 | Breakfast | €15 |
| R01 | Spa | €40 |
| R02 | Breakfast | €15 |
| R02 | Gym | €10 |
| R02 | Laundry | €25 |
| R03 | Gym | €10 |
| ServiceID | ServiceName | Price |
|---|---|---|
| SV01 | Breakfast | €15 |
| SV02 | Spa | €40 |
| SV03 | Gym | €10 |
| SV04 | Laundry | €25 |
| ReservID (FK) | ServiceID (FK) |
|---|---|
| R01 | SV01 |
| R01 | SV02 |
| R02 | SV01 |
| R02 | SV03 |
| R02 | SV04 |
| R03 | SV03 |
| GuestID | GuestName | GuestEmail |
|---|---|---|
| G01 | Liam | liam@mail.com |
| G02 | Mia | mia@mail.com |
| RoomNo | RoomType | Rate |
|---|---|---|
| 101 | Single | €80 |
| 205 | Double | €120 |
| ReservID | GuestID (FK) | RoomNo (FK) | CheckIn |
|---|---|---|---|
| R01 | G01 | 101 | 01/03 |
| R02 | G02 | 205 | 02/03 |
| R03 | G01 | 101 | 10/03 |
| ReservID (FK) | ServiceID (FK) |
|---|---|
| R01 | SV01 |
| R01 | SV02 |
| R02 | SV01 |
| R02 | SV03 |
| R02 | SV04 |
| R03 | SV03 |
| StudentID | Name | Address | DeptCode | DeptName | Modules |
|---|---|---|---|---|---|
| S001 | Ava | Dublin | CS | Comp Sci | M101 Databases (Dr Ryan, B+), M102 Networks (Dr Kelly, A) |
| S002 | Noah | Cork | CS | Comp Sci | M101 Databases (Dr Ryan, A-), M103 Web Dev (Dr Murphy, B) |
| S003 | Ella | Galway | BA | Business | M201 Marketing (Dr Walsh, A), M101 Databases (Dr Ryan, B+) |
| StudentID | Name | Address | DeptCode | DeptName | ModCode | ModName | Lecturer | Grade |
|---|---|---|---|---|---|---|---|---|
| S001 | Ava | Dublin | CS | Comp Sci | M101 | Databases | Dr Ryan | B+ |
| S001 | Ava | Dublin | CS | Comp Sci | M102 | Networks | Dr Kelly | A |
| S002 | Noah | Cork | CS | Comp Sci | M101 | Databases | Dr Ryan | A- |
| S002 | Noah | Cork | CS | Comp Sci | M103 | Web Dev | Dr Murphy | B |
| S003 | Ella | Galway | BA | Business | M201 | Marketing | Dr Walsh | A |
| S003 | Ella | Galway | BA | Business | M101 | Databases | Dr Ryan | B+ |
| StudentID | Name | Address | DeptCode | DeptName |
|---|---|---|---|---|
| S001 | Ava | Dublin | CS | Comp Sci |
| S002 | Noah | Cork | CS | Comp Sci |
| S003 | Ella | Galway | BA | Business |
| StudentID | ModCode | ModName | Lecturer | Grade |
|---|---|---|---|---|
| S001 | M101 | Databases | Dr Ryan | B+ |
| S001 | M102 | Networks | Dr Kelly | A |
| S002 | M101 | Databases | Dr Ryan | A- |
| S002 | M103 | Web Dev | Dr Murphy | B |
| S003 | M201 | Marketing | Dr Walsh | A |
| S003 | M101 | Databases | Dr Ryan | B+ |
| ModCode | ModName | Lecturer |
|---|---|---|
| M101 | Databases | Dr Ryan |
| M102 | Networks | Dr Kelly |
| M103 | Web Dev | Dr Murphy |
| M201 | Marketing | Dr Walsh |
| StudentID (FK) | ModCode (FK) | Grade |
|---|---|---|
| S001 | M101 | B+ |
| S001 | M102 | A |
| S002 | M101 | A- |
| S002 | M103 | B |
| S003 | M201 | A |
| S003 | M101 | B+ |
| DeptCode | DeptName |
|---|---|
| CS | Comp Sci |
| BA | Business |
| StudentID | Name | Address | DeptCode (FK) |
|---|---|---|---|
| S001 | Ava | Dublin | CS |
| S002 | Noah | Cork | CS |
| S003 | Ella | Galway | BA |
| ModCode | ModName | Lecturer |
|---|---|---|
| M101 | Databases | Dr Ryan |
| M102 | Networks | Dr Kelly |
| M103 | Web Dev | Dr Murphy |
| M201 | Marketing | Dr Walsh |
| StudentID (FK) | ModCode (FK) | Grade |
|---|---|---|
| S001 | M101 | B+ |
| S001 | M102 | A |
| S002 | M101 | A- |
| S002 | M103 | B |
| S003 | M201 | A |
| S003 | M101 | B+ |
References
Sources used to build this material
Happy studying!
Databases are the foundation of every modern application