Give a table that is in Third Normal Form but violates Boyce-Codd Normal Form, and explain what structural feature makes that possible.
answer
- 3NF escape hatch: right side is prime
- BCNF removes the prime exception
- gap needs overlapping candidate keys
- student-course-teacher; course -> teacher
- zip -> city in (street, city, zip)
basics
~20 sTake (student, course, teacher) where each course has one teacher and a student takes a course from one teacher. Candidate keys are (student, course) and (student, teacher). The dependency course to teacher has a non-superkey determinant, but teacher is part of a candidate key, so 3NF permits it and BCNF does not.
solid answer
~50 s3NF allows a non-trivial X -> A where X is not a superkey, provided A is a **prime** attribute (part of some candidate key). BCNF deletes that escape hatch. So the two forms can only differ when a prime attribute is determined by a non-superkey — which requires **overlapping candidate keys**. The canonical example is `enrollment(student, course, teacher)` with the rules: a course is taught by exactly one teacher (`course -> teacher`), and a student takes a given course from exactly one teacher. Candidate keys are `(student, course)` and `(student, teacher)`; they overlap on `student`. `course -> teacher` has determinant `course`, which is not a superkey, so BCNF is violated — but `teacher` is prime, so 3NF is satisfied. The consequence is real redundancy: the fact "Databases is taught by Kim" is repeated for every enrolled student. A shorter example is `(street, city, zip)` where `zip -> city`.
code
text · 11 linesR(student, course, teacher)
FDs: course -> teacher
(student, course) -> teacher
(student, teacher) -> course
closure(student, course) = {student, course, teacher} -> candidate key
closure(student, teacher) = {student, teacher, course} -> candidate key
closure(course) = {course, teacher} -> NOT a superkey
course -> teacher : determinant not a superkey -> BCNF violated
teacher is prime -> 3NF satisfiedgo deeper
Know that BCNF is stricter than 3NF and be able to recite the student-course-teacher example even if the closure arithmetic is shaky.
Derive it: list the dependencies, compute both candidate keys, show that course is not a superkey while teacher is prime, and name overlapping keys as the enabling condition.
Move quickly to consequences — which anomaly you would see in production, what the decomposition costs in enforcement, and how you would spot the pattern in an existing schema.
Treat it as a modelling signal: a junction table holding an attribute of one parent. Discuss whether to decompose, and what enforcement mechanism replaces the key you gave up.
## The one-clause difference between the two forms Both normal forms are stated over non-trivial functional dependencies X -> A. - **BCNF:** X must be a superkey. Full stop. - **3NF:** X must be a superkey **or** A must be a *prime attribute* — a column belonging to at least one candidate key. Everything in BCNF is therefore in 3NF, and the only tables that separate them are those with a non-superkey determinant pointing at a prime attribute. For a prime attribute to be determined by something that is not a superkey, the table must have more than one candidate key and those keys must share at least one column. That structural feature — **overlapping composite candidate keys** — is the whole answer to "what makes the gap possible". ## The canonical example, worked Relation `enrollment(student, course, teacher)` under two business rules: 1. Every course is taught by exactly one teacher: `course -> teacher`. 2. For a given course, a student is taught by exactly one teacher: `(student, course) -> teacher`. Because a teacher teaches only their own courses, `(student, teacher) -> course` also holds. Compute closures: `(student, course)` closes to all three columns, and so does `(student, teacher)`. Both are minimal, so both are candidate keys, and they overlap on `student`. Every column is prime. Now test `course -> teacher`. Is `course` a superkey? No — its closure is `{course, teacher}`, which misses `student`. So BCNF is violated. Is `teacher` prime? Yes, it is in the key `(student, teacher)`. So 3NF is satisfied. The table sits exactly in the gap. ## The redundancy is not theoretical With thirty students enrolled in *Databases*, the pair (Databases, Kim) is stored thirty times. If Kim hands the course to Lee, all thirty rows must change together; a partial update leaves the table asserting two teachers for one course, which the business rules say is impossible. You also cannot record who teaches a brand-new course until the first student enrolls, and dropping the last student erases the assignment. These are the classic update, insertion and deletion anomalies — 3NF simply does not promise to remove them when the redundant column happens to be prime. ## A smaller example to keep in your pocket `address(street, city, zip)` with `zip -> city` and `(street, city) -> zip`. Candidate keys: `(street, city)` and `(street, zip)`, overlapping on `street`. `zip -> city` violates BCNF because `zip` is not a superkey, while 3NF is happy because `city` is prime. The redundancy: the mapping from a postcode to its city is repeated on every address in that postcode. ## Fixing it Decompose on the violating dependency. For the enrollment case: `course_teacher(course PRIMARY KEY, teacher)` and `enrollment(student, course)` with `(student, course)` as the key. Now each course-teacher fact is stored once, and the join on `course` reconstructs the original relation exactly — the split is lossless because `course` is a key of the first table. The cost shows up immediately: the dependency `(student, teacher) -> course` no longer lives inside any single table, so the database can no longer enforce it with a key alone. That loss of **dependency preservation** is the standard reason a designer may consciously stop at 3NF, and it is the natural next question in an interview. ## How to recognise the situation in a real schema The smell is a table whose natural key you could write two different ways, both composite, both sharing a column — typically a junction table that has quietly absorbed an attribute belonging to one of its parents. `enrollment` acquired `teacher`, which is really a property of `course`. Pushing the attribute back to the entity that owns it is the same move as the BCNF decomposition, arrived at by modelling instinct instead of dependency algebra.
- Can a table with exactly one candidate key ever be in 3NF but not BCNF?No. With a single candidate key, a violating dependency would need a non-superkey determinant pointing at a prime attribute, and every prime attribute belongs to that one key. Any such dependency turns out to make the determinant a superkey after closure, so the two forms coincide. The gap requires at least two overlapping candidate keys.
- What concretely goes wrong if you leave the enrollment table as it is?The course-to-teacher fact is duplicated per enrolled student, so reassigning a teacher becomes a multi-row update that can be applied partially and leave contradictory rows. You also cannot record a teacher for a course with no enrollments, and deleting the last enrollment loses the assignment. Enforcing course -> teacher then requires a trigger rather than a key.
saying these in an interview costs you the question
- Claiming 3NF and BCNF are the same thing in practice, without naming the overlapping-candidate-key condition that separates them.
- Saying the enrollment table violates 3NF as well — it does not, because teacher is a prime attribute.
- Describing course -> teacher as a transitive dependency on a non-prime attribute; the whole point is that teacher is prime.
- Asserting the difference only appears in artificial textbook tables, when junction tables that absorbed a parent's attribute hit it routinely.
- Confusing a candidate key with the chosen primary key, and so failing to notice the second key that creates the overlap.