- Describe entities, attributes and relationships in an ER model and turn 1:1, 1:N and M:N relationships into tables
- Find functional dependencies and candidate keys, and explain update, insert and delete anomalies
- Decompose a table losslessly into 2NF, 3NF and BCNF and judge whether dependencies are preserved
Imagine that course registration is kept in one big Excel sheet: every row has the student's name, city, the course title, the teacher and the score. When a teacher changes their surname, it must be fixed in hundreds of rows — miss one and the database contradicts itself. A new course can't be added until someone enrols, and when the last student leaves a course, the course itself disappears. In this lesson we learn to design a database so that every fact is stored in exactly one place. The scientific name for this is normalisation, and our practice database is built by exactly these rules.
The ER model: entities, relationships, cardinality
Design starts not with tables but with a conceptual model. An entity is a thing we store data about: a student, a course, a product. An attribute is one of its properties: a name, a price. A relationship connects entities: a student enrols in a course, a customer orders a product. Peter Chen proposed this model in 1976 in the form of entity–relationship (ER) diagrams.
Tells how many instances of one entity can be related to one instance of another: one-to-one (1:1), one-to-many (1:N) or many-to-many (M:N). Cardinality decides which table the foreign key goes into.
| Relationship | Example | How it is built in tables |
|---|---|---|
| 1:1 | student — student ID card | a UNIQUE foreign key in the second table, or a shared primary key |
| 1:N | customer — orders | a foreign key on the “many” side: orders.customer_id |
| M:N | students — courses | a junction table with two foreign keys: enrollments |
Functional dependencies and keys
The core idea of normalisation is the functional dependency (FD). X → Y means “the value of X uniquely determines the value of Y”: course_id → teacher — if we know the course, we know the teacher. An FD is not an accident of the data but a business rule: we learn it from domain experts, while the current rows of a table can only refute it.
- Xthe determinant — a set of attributes
- Ythe set of dependent attributes
- rany valid state of the table (relation)
- t₁, t₂any two rows of the table; t[X] — the row's values in the columns X
Two rows that agree on X must also agree on Y.
A set of attributes that determines all the other attributes is a superkey; a superkey from which no attribute can be removed is a candidate key. One of the candidate keys is chosen as the primary key. An attribute that belongs to some candidate key is called a prime attribute — we will need this distinction to tell 3NF and BCNF apart.
Anomalies: why redundancy is dangerous
- Update anomaly — the same fact sits in several rows, and when one copy changes the others stay old.
- Insert anomaly — one fact can't be recorded without another (adding a course that has no enrolments yet).
- Delete anomaly — deleting one fact destroys another (the course's teacher is lost together with the last enrolment).
-- a denormalised copy: the teacher is repeated in every row
CREATE TABLE report_flat AS
SELECT e.student_id, s.first_name, e.course_id, c.title, c.teacher, e.score
FROM enrollments AS e
JOIN students AS s ON s.id = e.student_id
JOIN courses AS c ON c.id = e.course_id;
-- the name is corrected in one row only
UPDATE report_flat SET teacher = 'R. Safarov'
WHERE course_id = 1 AND student_id = 1;
SELECT course_id, teacher, COUNT(*) AS rows_with_it
FROM report_flat
WHERE course_id = 1
GROUP BY course_id, teacher
ORDER BY teacher;▸ Expected output
course_id | teacher | rows_with_it 1 | R. Safarov | 1 1 | Ramin Səfərov | 3
courses only.Normal forms: from 1NF to BCNF
| Form | Rule | Typical violation |
|---|---|---|
| 1NF | one atomic value per cell, no repeating groups, rows are distinguished by a key | phones = '050…, 055…' |
| 2NF | 1NF + every non-prime attribute depends on the whole candidate key, not on part of it | key (student_id, course_id), but student_id → city |
| 3NF | 2NF + no non-prime attribute depends on another non-prime attribute (no transitive dependency) | course_id → teacher → teacher_phone |
| BCNF | for every non-trivial X → Y, X is a superkey | teacher → subject, although teacher is not a key |
Given the table report(student_id, first_name, city, course_id, title, teacher, score) with the key (student_id, course_id). FDs: student_id → first_name, city; course_id → title, teacher; (student_id, course_id) → score. Which normal form is it in, and how should it be decomposed?
Show solutionHide solution
2)
first_name and city depend on only part of the key (student_id) — a partial dependency, so 2NF is violated. The same goes for title and teacher.3) One table per determinant:
students(student_id, first_name, city), courses(course_id, title, teacher), enrollments(student_id, course_id, score).4) Check: in each table the only determinant is its key — the result is in BCNF and is exactly the structure of our practice database.
A decomposition must be lossless: joining the parts must give back the original table with no extra and no missing rows. For a split into two parts we check this with Heath's theorem: the common columns must be a key of one of the parts.
- R₁, R₂the attribute sets of the two tables produced by the decomposition (R₁ ∪ R₂ = R)
- R₁ ∩ R₂the common attributes — the columns the
JOINis done on
If the condition holds, the decomposition is lossless: R = R₁ ⋈ R₂.
lessons(student, subject, teacher): each teacher teaches only one subject (teacher → subject), and a student has one teacher per subject ((student, subject) → teacher). Is the table in 3NF? In BCNF? How can it be brought to BCNF, and what is lost?
Show solutionHide solution
(student, subject) and (student, teacher). All three attributes are prime.2)
teacher → subject: teacher is not a superkey, but subject is prime — 3NF allows this, BCNF does not.3) BCNF decomposition:
teachers(teacher, subject) and assignments(student, teacher). The common attribute teacher is the key of the first table — lossless by Heath's theorem.4) The price: the dependency
(student, subject) → teacher can no longer be checked within one table; a trigger or application code must stop a student from getting two teachers for the same subject.When denormalisation is right
Normalisation is ideal for everyday transactions (OLTP): many small writes, accuracy, no contradictions. Analytical warehouses (OLAP), however, are mostly read, so they are denormalised on purpose: a “star schema” has a fact table (sales) in the centre surrounded by wide dimension tables (product, customer, date), and reports need only a few JOINs. The golden rule: design in 3NF first, and denormalise only when there is a measured performance problem — and always together with a synchronisation mechanism (a trigger, a view, a nightly refresh).
Rebuild the “flat” report for the Mechanics course from the normalised tables: the student's first name, city, course title, teacher and score. Sort by score descending. (With a lossless decomposition, JOIN gives back the original table exactly.)
SELECT s.first_name, s.city, c.title, c.teacher, e.score
FROM enrollments AS e
-- join students and courses
WHERE c.title = 'Mechanics'
ORDER BY e.score DESC;▸ Expected output
first_name | city | title | teacher | score Fidan | Naxçıvan | Mechanics | Ülviyyə Axundova | 94 Murad | Gəncə | Mechanics | Ülviyyə Axundova | 81 Rəşad | Bakı | Mechanics | Ülviyyə Axundova | 77 Elvin | Sumqayıt | Mechanics | Ülviyyə Axundova | 68
Check that the dependency teacher → subject holds in the current data: for each teacher show the number of different subjects (subjects), sorted by teacher. If every value is 1, the data does not refute the dependency.
SELECT teacher
-- number of different subjects
FROM courses
GROUP BY teacher
ORDER BY teacher;▸ Expected output
teacher | subjects Elnur Qasımov | 1 Nərmin Vəliyeva | 1 Ramin Səfərov | 1 Samir Hacıyev | 1 Sara Mitchell | 1 Ülviyyə Axundova | 1
Key points
- Design starts with an ER model; an M:N relationship is built with a junction table that has two foreign keys.
- The functional dependency
X → Yis a business rule: rows equal on X must be equal on Y. - Redundancy causes update, insert and delete anomalies; normalisation stores every fact in one place.
- 2NF removes partial dependencies and 3NF transitive ones; in BCNF every determinant is a superkey.
- A decomposition must be lossless (Heath's theorem); 3NF can always preserve dependencies, BCNF not always.
- OLTP uses 3NF, while analytical warehouses use a deliberately denormalised star schema.
Check yourself
10 questions. Every correct answer earns XP.