Database Normalization: Closure, Minimal Cover, and the 3NF Synthesis Algorithm
Prerequisite Knowledge
This lecture builds on the following concepts from earlier lectures. If any feel unfamiliar, review the linked notes before proceeding.
Previously Covered in This Subject
- Functional dependencies — covered in Lecture 4 (4.3 Functional Dependencies)
- The four guidelines for a good relation — covered in Lecture 4 (4.1 Why Normalization: Four Guidelines for a Good Relation)
- Normal forms: 1NF, 2NF, 3NF, BCNF — covered in Lecture 4 (4.4 The Normalization Process)
- Keys: super key, candidate key, primary key — covered in Lectures 2 (2.4) and 3 (3.4)
- From ER diagram to relational schema — covered in Lecture 3 (3.6)
- NoSQL and document databases — covered in Lecture 3 (3.10)
5.1 Why Database Systems Exist — Recap of the Four Properties of a Good Database
5.1.1 The Reason Database Systems Exist
Hook. Why does managing data deserve its own discipline, when programming languages are already so powerful?
Every application we build — desktop, enterprise, mobile — has one central component: managing data. Data management exists to solve a problem and to give a better, more personal experience. We build applications in the first place to reach more people: a class of a hundred people can become a hundred times that through an application, and the same idea carries to agriculture, healthcare, and every domain we want to impact. Through an application you can reach far more people, solve more problems, and add value to many lives.
Data management needs its own discipline because traditional programming languages share the same limits. Whether you use functional languages (Scala, Haskell), imperative languages (Java, C), object-oriented languages, or logic programming languages (Prolog), they are all weak at four things:
- Storing data. A program's variables exist only while the program runs; a language alone gives you no way to keep data safe after the program stops.
- Storing constraints. You can write
ifchecks, but the language does not guarantee, as a rule, that every phone number is unique or that every employee belongs to a department. - Retrieving data efficiently. Finding "all students enrolled in Database Design" means writing a loop over everything; there is no built-in, optimized way to fetch a subset.
- Retrieving data concurrently. Two users reading and updating the same data at the same time need careful coordination; a language alone leaves this to you, badly.
That gap is what database systems fill.
We have already walked one path in this course: a user gives you a requirement; as the database designer, administrator, and team manager, you create a diagram (an entity-relationship diagram), then you convert the diagram into a relational schema. That is a good way to store data, but it is not a proof. We have no mathematical certainty that the relation we drew is a good relation and will behave as expected. Normalization is the machinery that supplies that certainty.
5.1.2 The Four Properties of a Good Database
A good database design is judged on four properties.
Good semantics. The database explains itself. Relation (table) names and attributes are clear, so the design team, the application development team, and the maintenance team can all read the same schema and understand it. In real projects these are often separate teams: you may sit in the database design team while a different group writes the application and yet another maintains and scales it. A schema with clear semantics lets every team create and maintain the software.
Least redundancy and least update anomalies. Redundancy (the same data stored in more than one place) is the enemy. Consider a tiny table where the same person's ID and name repeat once per phone number:
| ID | Name | Phone |
|---|---|---|
| 1 | Ana | 111-0001 |
| 1 | Ana | 111-0002 |
| 2 | Ben | 111-0003 |
If Ana changes her name to Anya, a change of name forces an update at every occurrence — here two places, in a real table dozens. That is an update anomaly — hazardous and troublesome, because if we update only one of the two rows, the data contradicts itself. The two related problems are the insert anomaly (you cannot record a new phone number for Ana without repeating her name again, and you cannot record a person with no phone number at all) and the delete anomaly (deleting Ana's last phone number would silently delete Ana herself). The primary cause of all three — insert, update, delete — is redundancy.
Least null entries. Nulls (missing values) block joins, block proper explanation of the database, and waste a lot of space. If half the rows in a relation have an empty grade column, any query that joins on grade simply drops those rows, and the schema no longer "explains itself" cleanly.
Least spurious tuples. When normalization splits one relation into several, joining them back must not produce new false tuples — junk rows that did not exist in the data. A spurious tuple (the professor's spoken phrase for these false rows) is a row created by joining that matches no real-world record, and such junk rows would block strong decision making: a report that counts employees could silently count rows that no employee corresponds to.
Pitfalls of ignoring the four properties. A schema with bad semantics forces every new team member to guess what each column means. A redundant schema turns every name change into a multi-row edit that is easy to do half-way. Null-heavy schemas quietly drop rows from joins. And lossy joins produce phantom rows that corrupt reports. Each of the four properties is cheap to ignore at design time and expensive to repair later — that is why the rest of this session builds a mathematical method to guarantee them.
5.1.3 The Normal Forms So Far — 1NF, 2NF, 3NF, BCNF
We have already covered four normal forms. Each is a rule about the functional dependencies allowed inside a relation, and each stricter rule removes one class of redundancy.
First normal form (1NF): every record is unique, and every cell entry is a distinct, atomic value. No repeating groups of phones inside one cell, no two identical rows.
Second normal form (2NF): full functional dependency — no non-prime attribute may depend on only part of a candidate key. The professor's compressed phrasing was "the left-hand side alpha should be a complete candidate key, or beta should be a prime attribute"; the standard definition is that every non-prime attribute must be fully dependent on every candidate key, meaning no partial dependency on a proper subset of a key. Both versions say the same thing: the only allowed dependencies run from the whole key, never from a slice of it.
Third normal form (3NF): for every functional dependency , either is a superkey or every attribute in is a prime attribute. The instructor compressed this to "alpha is a superkey and beta is a prime attribute"; the standard form is the or-version above — only one of the two conditions needs to hold, and that subtle "or" is what lets 3NF always be achievable while keeping the original dependencies (Section 5.8).
Boyce-Codd normal form (BCNF): for every functional dependency , must be a superkey — nothing else is allowed.
Intuition: a staircase of rules. Each normal form forbids one more kind of dependency. 1NF forbids non-atomic cells. 2NF forbids partial dependencies (on part of a key). 3NF also forbids a non-prime attribute determining a non-prime attribute. BCNF forbids everything except dependencies whose left side is a superkey. So the hierarchy is BCNF ⊂ 3NF ⊂ 2NF ⊂ 1NF: every BCNF relation is automatically in 3NF, every 3NF relation in 2NF, and so on — but not the other way round.
5.1.4 Key Terminology — Superkey, Candidate Key, Primary Key, Prime Attributes
- Superkey (also just called a key): a set of attributes whose values are distinct in different tuples — no two record entries share the same combination. It is what makes rows unique. Formally, a set is a superkey of relation if — the set determines every attribute.
- Candidate key: when a relation has more than one superkey, each minimal superkey (one from which no attribute can be removed without losing uniqueness) is a candidate key. In other words: when a relation has more than one key, each of them is a candidate key.
- Primary key: the one candidate key we choose to identify rows in practice. The others remain candidate keys — they are still unique, we simply did not crown them.
- Prime attribute: any attribute that belongs to some candidate key. Every attribute that is part of any candidate key is prime; every attribute outside all candidate keys is non-prime.
Worked micro-example. In a relation Student(roll_no, email, phone), suppose both roll_no and email are unique per student. Then {roll_no} and {email} are superkeys, and since neither can be shrunk, both are candidate keys. We pick roll_no as the primary key. Then roll_no and email are prime attributes, while phone — in no candidate key — is non-prime. Sense-check: the superkey is what separates one row from another; the candidate key is the smallest such set; the primary key is the one we use; prime attributes are the ones inside some candidate key.
5.1.5 Two Ways to Learn a Theorem
A student asked whether we must implement all the normal forms to make the database better. The answer set the teaching method for the day. There are two ways to learn anything. One: give a practical example first, then reveal the theory that explains why the practice works. Two: give the theorem and its explanation first, then show how it applies in real life. This session follows the second path — theorems first.
The professor's analogy — Newton's laws. Think of Newton's first, second, and third laws: you learn the laws first, and application comes later. We do the same with normal forms. For now the goal is to be clear on what first, second, and third normal form and BCNF are, why each theorem exists, and why its logic is sound. Practice and real-life application will follow — and if the theorem is not clear by the end, hold the question and ask again. The analogy breaks where laws of motion are given once and for all, while database requirements keep changing — but the learning order is the same: the rule first, the use later.
Recap. A good database design satisfies four properties — clear semantics, least redundancy and least update anomalies, least null entries, least spurious tuples. Normal forms (1NF → 2NF → 3NF → BCNF) are the mathematical rules that guarantee these properties, and superkeys, candidate keys, primary keys, and prime attributes are the vocabulary the rules use. Next we look at the engine behind every normal form: functional dependencies and the redundancy they create.
5.2 Functional Dependencies Create Redundancy — Why Higher Normal Forms Are Better
5.2.1 The Core Mechanism — Whenever an Attribute Repeats, Its Determined Attributes Repeat
Hook. A database with more rules (functional dependencies) stores more copies of the same fact. Why would adding rules ever make things worse?
If there is a functional dependency from B to C, written — read "B determines C" — the meaning is simple: whenever the value of B repeats, the value of C repeats too. Suppose B1 appears in two rows and each row carries C1. Then the same C1 is stored twice — that is redundancy. Change C at one place, and every place where B repeats must change as well.
Worked example — ID number → name. In an enrollment table, the functional dependency holds: one ID number belongs to exactly one person. Suppose the same ID appears in ten rows (ten courses, ten phone numbers, ten anything). The person's name repeats at all ten places. Now the person changes their name — one spelling becomes another — and the change touches all ten places. Update five of them and the table contradicts itself: the same ID now maps to two names. Sense-check: every time B repeats, C is dragged along — so the number of copies of C equals the number of copies of B, and every edit of C is multiplied by that count.
Two everyday examples were worked through, and the instructor checked repeatedly that this point landed, because this small mechanism is the engine behind everything that follows. Course → textbook: wherever the course "Database Design" appears, the textbook name appears; change the textbook, and every occurrence must change.
The chain in full: functional dependencies → redundancies → uncertainty and anomalies. If the same data sits at twenty places and one place differs from the other nineteen, which one is correct? You cannot decide with confidence. Redundancy also creates resistance to insertion, update, delete, and insert anomalies. The bold statement of the session: the more functional dependencies a relation has, the more redundancies it carries. The fewer functional dependencies exist in a relation, the easier it is to update and the less redundant it is.
Intuition — the answer-sheet analogy. Imagine ten answer sheets, each showing the same roll number at the top, and each carrying the student's name printed next to it. The roll number repeats — so the name repeats. If the student's name changes spelling, every sheet must be reprinted. The dependency is the rule "one roll number, one name"; the redundancy is not the rule itself but the repeated copies the rule forces. Where the analogy breaks: a teacher might choose to leave old sheets unedited, but a database has no "old copy" — inconsistency is simply wrong data.
5.2.2 Second Normal Form Versus First
Why is 2NF better than 1NF? Consider a relation whose candidate key is a pair of attributes, and suppose a functional dependency runs from part of that key to some other attribute. Because the pair is a candidate key, the pair itself cannot repeat — by definition, rows are distinct on the key. But one member of the pair is not a key by itself, so it can repeat, and everything it determines repeats with it.
Worked example — a composite key. Consider Enrollment(class_id, course_number, textbook) where the candidate key is the pair (class_id, course_number) — each class meeting of each course is one row. If the dependency holds, then wherever "DDA-101" appears, its textbook appears too. The pair (class_id, course_number) never repeats, but course_number alone repeats in every row of the same course — and the textbook repeats with it. A 1NF table storing this is full of textbook copies. Sense-check: the key as a whole is unique, but a slice of the key is not, and that slice drags its determined attributes along.
Second normal form forbids exactly this: no dependency on a proper part of a candidate key. Satisfying 2NF removes one whole class of redundancy — the partial dependency (a dependency whose left side is a strict subset of a key). Every removed redundancy means less resistance to insertion, easier updates, and more confidence that the stored data is correct.
There is a natural objection: don't we remove even more by never repeating the primary key at all? Yes — a primary key appears only once in the relation, and that is by definition. The problem case is a part of a candidate key: it is not a key, so it can appear many times, and everything it determines repeats with it. That is the specific redundancy 2NF eliminates.
5.2.3 Third Normal Form Versus Second
3NF removes one more kind of dependency. Under 2NF, it is still allowed for a non-prime attribute (one outside every candidate key) to determine another non-prime attribute. Example: an email ID that is not part of any candidate key determines an address. Whenever the email ID repeats, the address repeats — still redundancy. 3NF says no: any non-prime attribute determining any non-prime attribute is not allowed either.
Worked example — non-prime → non-prime. In Student(roll_no, email, address), let roll_no be the only candidate key. Then email and address are non-prime. If the real world gives (one email, one home address), then two students sharing... no — two rows sharing one email would force the same address in both rows. The dependency is a promise the data must keep, and keeping it means repeating the address wherever the email repeats. 3NF demands the dependency itself be split out into its own relation. Sense-check: the redundancy here needs no key part at all — the determiner (email) is a plain non-key attribute, and that is exactly the case 2NF cannot see.
The fundamental logic is unchanged: functional dependencies lead to redundancy; redundancy leads to uncertainty and to update, delete, and insert anomalies. So the fewer functional dependencies exist in a relation, the better — easier to update, less redundancy. That submission is what carries the argument from 2NF to 3NF.
5.2.4 BCNF Versus 3NF and the Four-Property Test
Why is BCNF better than 3NF? BCNF allows only one kind of functional dependency: where is a superkey. The only functional dependencies that exist in a BCNF relation are those whose left side is a candidate key — nothing else may exist. When no other dependency exists, there is hardly any repetition left in the database. So BCNF gives the best result on all four properties of a good relation: least redundancy, least null entries, least spurious tuples, and the fewest anomalies.
| Normal form | What a dependency may look like | What is forbidden |
|---|---|---|
| 1NF | (no constraint on dependencies) | non-atomic cells, duplicate rows |
| 2NF | if is non-prime, then must be a complete candidate key | partial dependency: a non-prime attribute determined by a proper part of a candidate key |
| 3NF | is a superkey, OR every attribute of is prime | non-prime attribute determining a non-prime attribute |
| BCNF | must be a superkey, always | every other dependency |
The professor's salesman framing. The instructor refused to let the claim "BCNF is better than 3NF" pass as an assertion. His framing: "I am selling you the claim that BCNF is more good than 3NF. Do not accept it blindly — ask why and how." The point of the framing: a claim you can defend beats a claim you memorize, and the four properties give you the measuring stick to verify the claim yourself.
Students attempted the answer. One student started well — when a row is duplicated, higher normal forms apply stricter rules and we make sure the duplication caused by functional dependencies is removed — but then digressed. Another pointed at 3NF: non-prime attributes are not dependent on non-prime attributes, so updating one non-prime attribute does not force updates in many places. The instructor's verdict: ninety percent correct. The missing step was mapping the answer to the definition of a good relation: fewer functional dependencies mean less redundancy, and less redundancy better satisfies the four properties. That mapping is precisely what formal education trains — processing a thought, articulating it, and presenting it as a logical argument — which is why written examinations exist.
Pitfalls on this argument. (1) Confusing the key with a part of the key: the primary key never repeats — the member of a composite key repeats, and that is what creates copies. (2) Believing more functional dependencies means a "richer" or more constrained database: in this course's sense, more dependencies mean more redundancy, not more integrity. (3) Using the compressed 3NF rule as an AND: the standard rule is an OR, and BCNF is a separate, stricter rule — never collapse the two.
5.2.5 The Class Debate — Student Questions and Answers
Q: Does normalization depend on the requirements? If we need to make the database better, do we have to implement all the normal forms? A: The answer comes from watching how this session is taught. There are two ways to learn anything. One: give a practical example first, then explain the theory that makes the practice work. Two: give the theorem, explain it, then show how it applies in real life. This session follows the second path — the theorem comes first. Think of Newton's first, second, and third laws: you learn the laws, and only then do you apply them. So for now, focus on the theorem: what first, second, and third normal form and BCNF are, and why each exists. Practice and real-life application will come — and if your question is not answered by the end of this session, hold it and ask again.
Q: In a real-time scenario, everyone will go for BCNF, right? Or are there cases where only one normal form is enough — where following one normalization rule suffices? A: First: this is my claim, and I am selling it to you. I am telling you BCNF is more good than 3NF. Do not accept it blindly — ask why and how, unless you are clear that it is better because of the reasons I give. I am a salesman, and you are buying with your time. Second, the excursion: if BCNF is really better, why can't everyone take it? Because making that superior level of quality takes exertion, and maintaining it takes energy and effort. Sometimes the requirement itself says first normal form is enough, because we want more scalability and efficiency. Normalization creates more tables when we split relations — and you can guess why. In real life you may well end up with first or second normal form only.
Q: Why is third normal form better than second normal form? In 3NF, non-prime attributes are not dependent on non-prime attributes. If there are multiple non-prime attributes, updating one non-prime attribute would force updates in many places. Since that kind of dependency is absent in 3NF, we don't have to update that many times. So how is it more good? A: You are ninety percent correct. Now relate it to the definition of a good relation — the four properties of a good database design schema. Which property is better satisfied? Fewer functional dependencies mean less redundancy; less redundancy means less uncertainty and fewer update, delete, and insert anomalies. That is the answer: 3NF has fewer functional dependencies, so it has less redundancy, so it satisfies the four properties better. This is what formal education trains: processing a thought, articulating it systematically, and presenting the argument in a written form. That is why written examinations exist — don't underestimate the potential of the formal education you are going through.
Q: You said the primary key repeats and everything else repeats with it. Is the reverse possible — if the other attributes on the right side are updated, will the key get affected? A: That is a different question. If the ID number determines the name, then whenever the name changes, it has to be changed at every place the ID number appears. Suppose a person's name changes from one spelling to another — does the ID number also change? Maybe, maybe not; it depends on the organization. The point is the direction of the dependency: ID number → name is given, so the name repeats wherever the ID number repeats. Had the combination been a complete candidate key, it would appear in only one place. But a part of a candidate key is not the key, so it can appear many times — and everything it determines repeats with it. That is the submission: second normal form has less redundancy than first normal form.
Recap. A functional dependency means "wherever B repeats, C repeats" — and repeated copies are redundancy, which breeds uncertainty and insert/update/delete anomalies. Each higher normal form removes one class of dependency: 2NF kills partial dependencies, 3NF kills non-prime → non-prime dependencies, BCNF allows only superkey left sides. Fewer dependencies → less redundancy → the four properties are better satisfied. Next we ask the uncomfortable question: if BCNF is so good, why does the real world stay in 1NF and 2NF?
5.3 The Cost of Normalization — Why Not Everything Is in BCNF
5.3.1 Every Split Adds a Join
Hook. If BCNF is the best design, why do real-world databases stay in 1NF and 2NF? Because every normalization split is a trade — you pay for less redundancy with slower retrieval.
If higher normal forms are so good, why does the real world contain so many 1NF and 2NF relations? Because normalization splits relations, and every split has a price. To convert a relation that violates 3NF, we create two relations: one holds and , the other holds everything including . From then on, retrieval requires a join almost every time. Retrieval takes time; addition takes effort; maintaining the split is painstaking. So even though 3NF has less redundancy than 2NF, and BCNF less than 3NF, retrieving and maintaining them cost more.
Worked example — one split, one extra join. Suppose a university keeps Section(section_id, course_number, credit_hours). The dependency makes it violate 3NF (a non-prime attribute determined by a non-key attribute), so normalization splits it into R1(section_id, course_number) and R2(course_number, credit_hours). Now the question "what are the credit hours of the course in section S101?" needs two lookups joined on course_number instead of one row. One split = one extra join on every such query. Sense-check: the same answer is still available — it just costs a join each time, and joins grow with the size of the tables they combine.
Because of exactly this relation between splits and joins, some database schemas stay in 1NF or 2NF on purpose. When queries are light and no heavy join loads arrive, the team just stores everything together, does not worry about 1NF, 2NF, 3NF, or null entries, and enjoys fewer joins at retrieval time.
5.3.2 Denormalization as a Deliberate Choice
The engineering decision rule. If the effort required to convert to 3NF, maintain it, and use it is more than the benefit, then denormalize — bring the relation back to 2NF (or even 1NF). Denormalization is not laziness; it is a recorded, reasoned choice to trade redundancy for speed.
- When updates are the priority, prefer 3NF — fewer places to change, so each edit is cheap and safe.
- When fast retrieval dominates, accept 2NF with its redundancy: "it's okay that we will update it multiple times, but retrieval is faster; it's okay that we will have some redundancy, but it is easier for us to enter, easier to delete, easier to retrieve."
Indexes and other provisions also exist to make retrieval faster without abandoning normalization. An index is a pre-built lookup structure on a column — the database equivalent of a book's index — so the retrieval cost is cut at the storage layer rather than by storing extra data copies.
5.3.3 NoSQL and the Redundancy Trade-off
Real-world: many modern systems accept redundancy in exchange for retrieval speed. More and more databases that handle very large data volumes with heavy retrieval load are moving toward NoSQL systems such as MongoDB, Cassandra, and Neo4j. They store data together in JSON, convert it to BSON (Binary JSON — MongoDB's compact binary format for storage and transfer, pronounced "bee-son"; the professor's spoken term sounded like "BASAN"), and replication is easier. They may compromise somewhat on redundancy because retrieval is so heavily required and the data size is so large. Traditional relational systems, in contrast, exist to give mathematical certainty about the schema — which is exactly what normalization provides.
Assumptions & scope of the trade-off. The "normalize everything" advice assumes a stable schema and roughly balanced read/write loads. It breaks when (1) reads vastly outnumber writes and must be fast — each split adds a join to every read; (2) the data is document-shaped and retrieved whole (a user profile is one JSON object, not five joined tables); (3) availability and replication matter more than consistency, so each replica simply carries its own full copy. In those regimes, accepting redundancy is not a mistake — it is the correct engineering trade. The failure mode to avoid is accidental redundancy: denormalizing without a decision, which buys speed and keeps the anomalies too.
5.3.4 Student Questions on the Trade-off
Q: I understand the move from first normal form to second to third — we avoid functional dependencies and create separate tables, and retrieval takes more time because we have to get and combine data from multiple tables. But how do you talk about BCNF? Why BCNF is better is not yet clear. A: BCNF is better than 3NF because of what it allows. If there is a functional dependency , BCNF says the only thing I allow is being a superkey. The only functional dependencies that exist in a BCNF relation are those from a candidate key — no other functional dependency can exist in the relation. With no other functional dependency, there is hardly any repetition left in the database. And the decision is not made at the time of an update. It is made at design time: the moment we know a functional dependency exists, we split the relation so that the left-hand side becomes a candidate key of its own relation. Take name and ID number in a college: later the requirement may come that we want to allow the name to change. We deal with it right away. If name → ID exists and name is not a candidate key, we normalize beforehand — we create a separate relation in which name is a candidate key on its own. Any functional dependency we know now must have a superkey on its left-hand side. It is not at the time of updation — it is at the time of designing the database schema.
Q: Suppose a college system used name and ID together as a key, and later the requirement came that we want to allow the name to change. Is that BCNF? A: No. The decision has to be taken right away. If name and ID are there and there is a dependency from name to ID, and name is not a complete candidate key, then we normalize it beforehand and create a separate relation where name and ID are in a relation in which name is a candidate key in itself. Any functional dependency that we know exists now must have a superkey on the left-hand side. So it is not at the time when some updation occurs — we know that whenever this attribute repeats, that attribute repeats, and that is known at the time of designing the database schema, so we split across into two relations to make it BCNF. The misconception behind the question is that normalization reacts to updates; in fact, it reacts to known dependencies, which are a design-time fact.
Q: So if update is given more priority, we need to go to 3NF. If we need very fast retrieval, we may go with 2NF toward 3NF. Correct? A: It depends on the scenario. Sometimes we use indexes; sometimes we have other provisions for faster retrieval. But my point is why 2NF still exists. Once a 3NF schema is created, keeping every relation in BCNF as new relations are added is a problematic task, and sometimes retrieval takes a lot of joins, which creates issues. Also, with BCNF there are so many foreign keys — when more relations exist, many foreign keys lie here and there, and updates become a difficult task as well. So sometimes, for efficiency, we allow 2NF at the cost of redundancy. It is okay that we will update it multiple times, but retrieval is faster; it is okay that we will have some redundancy, but it is easier for us to enter, easier to delete, easier to retrieve.
Recap. Normalization is a trade, not a trophy: every split adds a join, and joins cost time. The decision rule is — updates dominate → 3NF/BCNF; retrieval dominates → 2NF (or 1NF) with redundancy, plus indexes. NoSQL systems (MongoDB, Cassandra, Neo4j) institutionalize the same trade at scale. Next we leave philosophy behind and build the machinery: the closure of a functional dependency set.
5.4 The Closure of a Functional Dependency Set (F+)
5.4.1 What F+ Means
Hook. A handful of given functional dependencies quietly imply dozens of others. Which ones? The closure answers that exactly — and nothing you build later may contradict it.
When we split a relation, two things must hold: every functional dependency we were given must be preserved, and no lossy relations may be created (joining the pieces must return exactly the original rows, with no spurious tuples). To guarantee preservation we need the complete set of functional dependencies derivable from the given set F. That set is the closure of F, written — all dependencies that follow logically from the ones we were given. All of them matter for building the final normal form.
A few given dependencies produce many derivable ones: given a set of three or four functional dependencies, applying the rules can create around thirty functional dependencies. Using all thirty to build a normal form is a troublesome task — creation is difficult and takes time. Two properties make the closure trustworthy: the rules produce all dependencies that exist (nothing is missing — the set is complete), and everything they produce is correct (nothing false is invented — the set is sound). Then, to work with a manageable set, we later build a minimal cover (Section 5.6).
5.4.2 Rule 1 — Reflexivity
Reflexivity. If Y is a subset of X — X is a superset of Y — then the dependency exists. In the professor's words: "given a set of functional dependencies from x to y, and if x is a superset of y, then this functional dependency exists."
This rule needs no "knowledge": it says only that a set of attributes determines its own parts. For example, (course_number, instructor_name) → course_number: if two rows agree on both the course number and the instructor, they certainly agree on the course number alone. Reflexivity is how a composite left side always determines each of its own attributes. A dependency with is called trivial — it holds in every relation, no matter what the data says.
5.4.3 Rule 2 — Augmentation
Augmentation. If exists, then exists — we may add the same attribute(s) Z to both sides. The instructor's statement: "the augmentation rule says that functional dependencies from x to y exist, so x z to y z exists."
The name says it: we augment (grow) both sides by the same set Z. Why must it be the same Z on both sides? Because adding Z only to the left would be a stronger claim we cannot justify. Example: from , augmentation with instructor_name gives (course_number, instructor_name) → (credit_hours, instructor_name) — true by definition, since the same instructor_name sits on both sides, and the stepping stone for the transitivity chains in Section 5.5.
5.4.4 Rule 3 — Transitivity
Transitivity. If and , then . The instructor's statement: "from x to y and y to z exists, then x to z also exists."
This is the rule that actually creates new knowledge. Transitivity shows up constantly in the examples: because course_number → credit_hours, any superset containing course_number also determines credit_hours; because text → publisher, anything that determines text also determines publisher.
Worked example — chaining the rules. Given and , transitivity gives . Add reflexivity: (course_number, instructor_name) → course_number. Put them together with transitivity again: (course_number, instructor_name) → course_number → text → publisher, so the pair determines publisher. Each step is one rule; the chain is the proof. Sense-check: wherever the pair repeats, the course number repeats, so the text repeats, so the publisher repeats — the two-hop dependency really does hold.
The three rules above are called Armstrong's axioms. Two facts make them the complete toolbox: they are sound (every dependency they produce genuinely holds) and complete (every dependency that genuinely holds can be produced by them). Three more rules are often listed, but each is derivable from the axioms and saves steps: the union rule and together imply ; the decomposition rule implies and ; and the pseudotransitivity rule and imply .
Pitfalls with the rules. (1) The rules work on sets of attributes, so order within a left side is irrelevant and duplicates are meaningless: and are the same set. (2) Decomposition applies only to right sides: from you may not conclude — the composite left side acts as one unit (Section 5.5.6). (3) Reflexivity generates the trivial dependencies automatically — don't forget them when you count , and don't treat them as real-world facts.
5.4.5 The Attribute Closure X+ and Its Algorithm
The workhorse of everything that follows is the attribute closure. is the set of every attribute derivable from X using the given dependencies. The algorithm, in the professor's words: "Initially start with X plus is equal to X... for every attribute that can be derived from X plus... X plus is a superset of Y... add that here in this particular group... and repeat."
- Start with .
- For every functional dependency in F with , add all of Z to .
- Repeat step 2 until stops growing.
Worked micro-example. Let and compute . Start: . Pass 1: fires (A ⊆ A⁺), so ; does not fire yet (B was just added — check again). Pass 2: fires, so . Pass 3: no dependency fires, done. Sense-check: holds by transitivity, and indeed C sits inside the final closure — the closure materializes exactly the transitivity chains.
Why the attribute closure matters — keys. A set of attributes whose closure covers the whole relation is a key. Formally, X is a superkey of R exactly when . The attribute closure is the standard test for superkeys, candidate keys, and redundancy in one tool: it answers "what can we determine from this attribute set?" for any set you feed it. Section 5.5 applies it to a real university schema; Section 5.6 uses it to test which dependencies are redundant.
Recap. is the complete set of dependencies implied by F, generated by three sound and complete rules — reflexivity, augmentation, transitivity — plus derived helpers (union, decomposition, pseudotransitivity). The attribute closure is the fast way to materialize the implications of one attribute set, and it doubles as the candidate-key test. Next: four worked closures in the university schema.
5.5 Attribute Closure Worked in a University Schema
5.5.1 The Given Functional Dependencies
The working example is a university mini-world with the attributes class_id, course_number, credit_hours, section_id, instructor_name, text, classroom, capacity, and publisher. The given functional dependencies (reconstructed from the professor's spoken list; the set is internally consistent, and every example below checks out against it):
Read each dependency exactly as written. In particular, dependencies 2 and 3 say that the pair (course_number, instructor_name) — the two taken together — determines text, and the same pair determines classroom. Neither course_number alone nor instructor_name alone determines either of them (see 5.5.6). The pair (course_number, instructor_name) jointly determining classroom, plus dependency 5, is the textbook pattern: in the standard university schema, the pair (building, room_number) determines capacity, and here the pair behaves like the room identifier.
5.5.2 Worked Example — Closure of class_id
Find .
Start with class_id. Which dependency has class_id on its left side? None in the given set. So:
Nothing is derivable — the closure is the attribute itself. The instructor's answer to the class: "That includes class ID. And what else? Can we derive something from the class ID? No. So closure of class ID is just class ID." Sense-check: no dependency ever fires, the set stops growing immediately, and the conclusion is that class_id determines nothing beyond itself.
5.5.3 Worked Example — Closure of course_number
Find .
Start with course_number. Dependency 1 applies: course_number → credit_hours, so credit_hours enters. Do any other dependencies apply? The pair course_number + instructor_name → text does not apply, because instructor_name is not in the closure — and, critically, a composite left side does not decompose into its members (see 5.5.6). So:
A student suggested that from the course number we can read the subject, since the course belongs to a subject. The answer: a closure contains only what follows from the given functional dependencies, and none of them says course_number → subject. The closure answers a strict question: what all can we determine from this attribute, using only the functional dependencies we were given? Sense-check: two attributes inside — the starting one plus exactly what dependency 1 promises — and no chain can begin because the only dependency with course_number's new friend (credit_hours) on the left is none.
5.5.4 Worked Example — Closure of section_id
Find .
Start with section_id. Dependencies 6 and 7 fire: course_number and instructor_name enter. The closure now contains both, so the pair (course_number, instructor_name) is inside — dependencies 2 and 3 fire, adding text and classroom. Text brings publisher (dependency 4); classroom brings capacity (dependency 5); course_number brings credit_hours (dependency 1). So:
Every attribute except class_id. The instructor's remark: "section ID includes everything... it's like a primary key." A set of attributes whose closure covers the whole relation is a candidate key — section_id is one. Sense-check: the trace is a chain — section_id unlocks course_number and instructor_name; together they unlock text and classroom; those unlock publisher and capacity; course_number unlocks credit_hours. Only class_id is never reached, because no dependency leads to it.
5.5.5 Worked Example — Closure of (course_number, instructor_name)
Find the closure of the pair.
Start with both attributes. The pair contains course_number, so dependency 1 fires: credit_hours enters. Dependencies 2 and 3 fire directly: text and classroom enter. Text brings publisher (4); classroom brings capacity (5). Nothing in the set brings section_id or class_id. So:
The instructor's remark: "so it does not have class ID definitely." Since the closure misses class_id (and section_id), the pair is not a candidate key — yet it determines everything else in the relation. Whether the pair is a candidate key is a separate question; what the computation shows is that the pair determines all of these attributes. Sense-check: compare with 5.5.4 — the pair's closure is exactly section_id's closure minus section_id itself, which is consistent: section_id determines the pair, and the pair determines all the rest.
5.5.6 Student Questions on Closure
Q: If AB → CD is there, does that mean A → C and B → D? A: No, it does not. AB → CD means AB → C and AB → D — the combination AB together determines C, and the combination AB together determines D. It does not mean A → C, and it does not mean B → D. Neither alone implies anything about C or D. The same holds for any composite left side: course number and instructor name together determine text and classroom, but course number alone does not, and instructor name alone does not. Read the dependency exactly as it is given.
Q: On dependency 3 — how is course number and instructor name a candidate key? As an instructor teaching a database course, you may be handling multiple sections. Shouldn't section ID be the candidate key instead of course number and instructor name? A: Section ID is definitely a candidate key in this relation — you are right about that. But the question is different: what does the pair course number and instructor name functionally determine? It is given that course number and instructor name together determine text and together determine classroom. Read the functional dependency as it is given: whenever course number and instructor name repeat, text repeats; whenever they repeat, classroom repeats. You don't have to use anything beyond the given dependencies — it is given to us. Then, by transitivity, the pair determines publisher (because text → publisher) and capacity (because classroom → capacity), and because the pair contains course number and course number determines credit hours, the pair determines credit hours too. So the pair determines everything except class ID — and since it does not determine class ID, it is still not a candidate key. Whether it is a candidate key is a separate thing; what matters is that the pair determines all of these.
Q: From the course number we can read the subject — the course belongs to a subject. Why is subject not in the closure of course number? A: A closure contains only what follows from the given functional dependencies. Which functional dependency says course number determines anything besides credit hours? None in our set. So course number's closure is exactly course number and credit hours. The closure answers a strict question: what all can we determine from this attribute, using only the functional dependencies we were given? Not what we believe the real world says. The same idea shows the direction of keys: section ID determines course number, but course number does not determine section ID.
Recap. The attribute closure is a mechanical drill: start with the set, fire every dependency whose left side is inside, repeat until nothing new appears. The university schema shows the four behaviors that matter: an unattached attribute stays alone (class_id), a single determiner pulls one attribute (course_number), a chain-building attribute sweeps almost everything (section_id), and a pair can be a near-key without being a key (course_number, instructor_name). Closures only use the given dependencies — never real-world beliefs. Next we shrink the working set: the minimal cover.
5.6 The Minimal Cover of a Functional Dependency Set
5.6.1 Why We Need a Minimal Set
Hook. You cannot build a normal form from thirty dependencies — but three might do the same work. How do you find the smallest set with the same power?
Functional dependencies reveal all the redundancies, and redundancies are the parameter of good database design. But the full closure is huge — tens of dependencies from a handful — and building a normal form from all of them is a troublesome task. The minimal cover (also called the minimal set or canonical cover) is the smallest set of functional dependencies with the same power as the original set, and we use that minimal set to create the good relation. This is what will be required: a minimal set of functional dependencies out of the given set, used to create a relational schema in 3NF or BCNF.
A minimal cover has three formal properties (matching the textbook definition): every dependency has a single attribute on its right-hand side; no dependency can be removed and still leave an equivalent set; and no attribute can be removed from any left-hand side and still leave an equivalent set. Nothing is smaller without losing power — that is what "minimal" means.
5.6.2 Equivalence of Functional Dependency Sets
Two sets F and F' are equivalent when whatever can be derived from the original set can be derived from the new set — in symbols, . That equality of closures is the test. The definition of redundancy follows directly: a functional dependency is redundant exactly when removing it leaves an equivalent set. The same applies to a single attribute on a left-hand side: if can be replaced by and the two sets stay equivalent, then Y is redundant. The instructor's words: "if this set and that set are equivalent... their closure are same, then this functional dependency is redundant."
Worked micro-example — the equivalence test in practice. Let . Is redundant? Compute with all of F: . Compute without , using only : → adds B → adds C — . The two closures are the same, so is redundant and can be dropped. Sense-check: the remaining two dependencies reproduce the dropped one by transitivity — same power, one fewer rule.
5.6.3 The Reduction Procedure
To build a minimal cover from a given set F:
- Split right-hand sides. Turn every dependency into and . The instructor's words: "if we have a functional dependency from A to C, D... what we write is A to C and A to D. That is the initial step." Note this decomposition works on right sides only — a composite left side does not decompose (see 5.5.6).
- Remove redundant functional dependencies. Test each dependency : compute with all of F, then without this dependency. If the two closures are the same, the dependency is redundant — remove it.
- Remove redundant attributes from left-hand sides. For each left side XY in a dependency , test each member: compute (the closure with Y removed) and compare with the original closure of XY. If they are the same, Y is redundant — remove it and use .
After any removal, re-run the checks: a dependency that was not redundant can become redundant after another removal. The instructor emphasized the test in the abstract: either the complete functional dependency is redundant, or an attribute on the left-hand side is redundant — we find out which one by comparing closures.
Pitfalls in the reduction procedure. (1) Skipping the recheck: removing one dependency can make another redundant — the four-step example in Section 5.7 shows this happening. (2) Testing a left-side attribute against the wrong closure: always compare with the closure of the full left side under the current set; otherwise you can wrongly delete a necessary attribute. (3) Applying step 1 to left sides: from you may never split into and . (4) Forgetting that a minimal cover need not be unique — different removal orders can give different (equally valid) covers, so if your answer differs from a classmate's, compare powers, not sets.
Recap. The minimal cover is the smallest set of dependencies with the same closure as the original — so the same power. Equivalence is tested by closure equality; redundancy is tested by comparing closures with and without the candidate. Three steps — split right sides, drop redundant dependencies, drop redundant left-side attributes — then recheck after every removal. Section 5.7 runs the whole drill on a concrete set.
5.7 Worked Example — Minimal Cover of {B → A, D → A, AB → D}
5.7.1 Step 1 — Split Right-Hand Sides into Singletons
Given . Every right-hand side is already a single attribute, so there is nothing to split in this step. The set stays:
5.7.2 Step 2 — Check Each Functional Dependency for Redundancy
Compute the closure of each left side with all of F, then without the dependency under test. The instructor made the test explicit: "if with this functional dependency and without this functional dependency everything is same, then we can say that this functional dependency is redundant."
Test . With all of F:
So with F is . Without , using only :
(AB → D needs A, which is unreachable without ; needs D.) The closures differ, so is not redundant — keep it.
Test . With F: . Without , nothing fires from D: . The closures differ — keep .
Test . With F: ( adds A, then adds D). Without , using only : (D is unreachable — needs D). The closures differ — keep .
| Dependency under test | with F | without it | Verdict |
|---|---|---|---|
| keep | |||
| keep | |||
| keep |
5.7.3 Step 3 — Remove Redundant Attributes from Left-Hand Sides
The dependency survives, but one of the two attributes on its left side may be redundant. Test each.
Test removing B — is B redundant on the left of ? Replace by and compute with the remaining set :
so . Compare with the original : not the same — with A alone we cannot reach B. So B is not redundant — keep it. The instructor: "Had it been the same, then we would have said that b is redundant."
Test removing A — is A redundant on the left of ? Replace by and compute with :
This equals the original . Having A and not having A makes no difference — A is redundant on the left side. The instructor: "so having a and not having a does not make any difference at all... so here I can say that attribute a is redundant here."
The new set is:
5.7.4 Step 4 — Recheck the New Set
After any removal, the earlier checks must be repeated — the instructor applied the same rule to the new set.
Recheck in F'. With all of F': (via and ). Without , using only :
Same closure! is now redundant — remove it. The instructor's observation: "having this functional dependency and not having this functional dependency, the rule remains the same. So this is redundant now." This is the recheck rule in action: survived step 2, but after became , the path reproduces it.
Recheck . With the current set : . Without : . Not the same — keep it.
Recheck . With: . Without , using only : . Not the same — keep it.
5.7.5 The Final Minimal Cover and the Candidate Key
The minimal cover is:
No further minimal form can be formed: both dependencies have single-attribute left and right sides, neither is derivable from the other, and neither left side can be shrunk. This matches the textbook result for the same input set exactly. The candidate key: B, because
covers every attribute in the relation. The instructor: "candidate key we consider it. B is a candidate key because B plus is equal to A, B, D."
Sense-check of the whole drill. Start: three dependencies. End: two. Check the end against the start by computing closures: under , — the same as under F, and as under F. The dropped is recovered as by transitivity, so : same power, one rule fewer, and the surviving left sides are as small as possible.
Recap. The minimal-cover drill has four moves: split right sides, test dependencies by closure comparison, test left-side attributes the same way, then recheck everything — because a removal can make something else redundant, exactly as happened to in step 4. The result has the same power as the original three-rule set, and its candidate key is B. Next: this minimal cover feeds the 3NF synthesis algorithm.
5.8 The 3NF Synthesis Algorithm
5.8.1 The Three-Step Algorithm
Hook. Everything so far — closures, minimal covers, candidate keys — lands in one recipe that turns a dependency set into a good schema. The professor: "these are only three steps that are important for us to create a relational schema that is in 3NF."
The recipe, in the instructor's words:
- Find the minimal cover. Compute the minimal set of functional dependencies from the given set (Section 5.7).
- Create one relation per dependency. Whatever is on the left-hand side of a dependency in the minimal cover, create a new relation containing X and A.
- Add the key if it is missing. If no created relation contains a candidate key of the whole schema, create one more relation with the key attributes.
The result is a relational schema at least in 3NF. The instructor also recalled the older decomposition rule for a single violation: if does not satisfy 3NF, create a new relation R2 holding and , and keep a relation holding everything including . The synthesis algorithm generalizes that one-off repair into a systematic recipe for the whole set.
Why the key step exists — and why the algorithm deserves its name. A relation per dependency guarantees that every dependency from the minimal cover can be checked inside a single relation — the dependency preservation property (the reason we started with the minimal cover in the first place, Section 5.4.1). The third step guarantees that at least one relation contains a candidate key, which is exactly what makes the decomposition lossless: joining the relations on the key reproduces the original rows with no spurious tuples. The algorithm is called synthesis because it builds the schema by assembling one relation per dependency, rather than chopping a big relation apart.
5.8.2 Worked Application — From {B → D, D → A} to Two Relations
From Section 5.7 we have the minimal cover and the candidate key B. Apply the algorithm:
- creates the relation . B is a candidate key of R1.
- creates the relation . D is a candidate key of R2.
- Key check: B already appears in R1, so no third relation is needed.
The final schema:
Both relations are in 3NF. The instructor's words: "create two relations. B, d — in which b is a candidate key. And d, a — where d is a candidate key. Is there any relation in which candidate key is there? Yes. There is one relation. Candidate key."
Verification of the result. (1) Dependency preservation: lives inside R1 and inside R2 — both checkable within a single relation. (2) Losslessness: joining R1 and R2 on the shared attribute D reproduces the original relation; the join key D is a candidate key of R2, and R1 keeps the global key B, so no spurious tuples appear. (3) Normal form: in R1, the only dependency is with B a superkey — 3NF (and BCNF) hold; in R2, with D a superkey — again 3NF and BCNF. Sense-check: two relations, both dependencies preserved, key present, no junk rows — the three promises of the algorithm all hold.
5.8.3 Where This Fits — Chapter Roadmap
Q: Which chapter is this — I completely lost track? A: This is Chapter 14 and Chapter 15. Relational algebra is a portion that will be covered from the next point onwards; relational algebra and SQL come later. So today's discussion covered Chapter 14 and Chapter 15.
The agenda in one paragraph, as the instructor summarized it: we start with a set of functional dependencies that carry redundancy, and we want least redundancy. Normal forms exist to achieve that, and our agenda is a relational schema that satisfies a normal form — the mathematical certainty of a good relation. Functional dependencies are the basis of redundancies, so we find the minimum set of functional dependencies: if F has four dependencies, remove the redundant ones and we are left with three or two. We find the candidate key, and we run the synthesis algorithm to create the relational schema. Once created, that is a good relation in 3NF or BCNF — a very good database design schema.
Recap — the whole recipe in one breath. Given a set of functional dependencies: find the minimal cover (fewest rules, same power), find a candidate key (an attribute set whose closure covers the relation), then synthesize — one relation per minimal-cover dependency, plus a key relation if the key appears in none. The output is a dependency-preserving, lossless schema in 3NF: the mathematical certainty we wanted from the very first section. The overall objective is not just how each algorithm runs, but why and what we are doing: why we need functional dependencies, what normalization is, and how it defines the relational schema. The how — finding closures, minimal covers, and candidate keys, then running the synthesis — needs practice, and practice is the next step.
Exam Guidance Summary
The mid-semester exam (closed book, about five weeks away). This is likely the only closed-book examination in the course, and that choice matters for how you prepare. Expect a mix: some theoretical questions — the instructor wants to evaluate how many of you have really grasped the concept — plus practical implementation questions. The stated question patterns:
- Given a customer specification (one paragraph, not two or three pages), create an ER diagram.
- Given an ER diagram, convert it into a relational schema.
- Given some functional dependencies, find out which normal form the relation is in, then convert it to 3NF or BCNF (the instructor said "third or fourth normal form" — the fix in either case is the machinery of this session: closures, minimal covers, synthesis).
- Practical scenarios like creating a table.
Exam note: the syllabus is everything covered until the class right before the mid-semester exam.
The final exam (open book). The implementation questions sit at a different level. For any given scenario and problem, you must answer on four levels: (1) specify the implication of the problem — if the schema is in a certain state, what follows? For example, the user cannot access concurrently, so performance degrades; (2) propose a solution — two or three options; (3) articulate in a plain way which option satisfies which requirement, and state the implication of the solution: what effort, time, and resources the solution needs; (4) give your verdict — based on the analysis, the problem is this, it has this implication, these solutions exist, they take this much effort and solve that much of the problem, so we follow this option.
Study tips given explicitly. Make notes, revise the previous material before entering, and revise the notes again after the session — this first basic habit helps you recollect things so that even in a closed-book exam the theory is at your fingertips, and you can score freely in those marks. Practice very diligently during the sessions — the sessions exist primarily for practice. Use the recorded materials, approach the instructor one-to-one (half-hour time slots are reserved for help), and ask questions among classmates — when a doubt appears, put it in the group so whoever is available can reply, or call and use a voice note; the answer, right or wrong, gets corrected there. Asking in a portal can feel like resistance, but the group is open.
Exam note: what is repeated is exam gold. The course repeats key ideas multiple times on purpose — "since the course is so simple, the things where you are repeating multiple, multiple times, it is easier for you to answer them in your examinations."
Exam note: expect a question to compute attribute closures and find candidate keys. Know the three rules — reflexivity, augmentation, transitivity — and the composite-left-side rule (AB → CD means AB → C and AB → D, never A → C alone).
Exam note: expect a question to reduce a given set of functional dependencies to its minimal cover (the full closure is too big to work with), then to synthesize the 3NF schema — one relation per minimal-cover dependency, plus a key relation if the key appears in none.
Exam note: understand the trade-off argument. Be ready to argue why real schemas sometimes stay in 1NF or 2NF — every split adds a join, retrieval takes time, maintenance takes effort, and BCNF spreads foreign keys across many relations — and to recommend 3NF when updates dominate versus 2NF when retrieval dominates. This kind of implication–option–verdict reasoning is exactly what the open-book final tests.
Assignment guidance. The assignment is individual. The requirements document shared as a sample is only a sample — you create your own assignment by choice. Expect twenty to fifty sample scenarios across supply chain, healthcare, finance, and insurance; pick any one (or your own real-world application), and use your assumptions properly. It is not required that you follow the same template — any template works, or even simple plain English, as long as you are satisfied that whatever the customer is specifying is captured in the requirement. The due date is written in the handout, which already describes what you need to do.
Key Industry Applications
- Real-world: large-scale systems increasingly accept redundancy for retrieval speed. More and more databases that face very large data sizes and heavy retrieval loads move toward NoSQL systems — MongoDB, Cassandra, and Neo4j were named. They store data together in JSON, convert to BSON (binary JSON) for storage, and benefit from easier replication. Redundancy is a deliberate compromise there; mathematical certainty about the schema is the relational world's answer, and normalization is how it is achieved.
- Real-world: denormalization is standard industry practice. When the effort to convert to and maintain 3NF exceeds the benefit, teams deliberately keep 2NF (or 1NF) relations: faster retrieval, easier entry, easier deletion, at the cost of updating the same value in several places. Indexes and other provisions speed up retrieval without giving up normalization.
- Real-world: the motivation for applications is impact — an application reaches a hundred times more people than a class session can. Agriculture, healthcare, and any other domain gain scale through software, and every such application, desktop, enterprise, or mobile, is built around managing data — which is why database design shows up in every industry.
- Real-world: programming-language ecosystems (functional languages such as Scala, plus imperative, object-oriented, and logic languages) all hit the same wall — storing data, storing constraints, retrieving efficiently, and retrieving concurrently — which is why database systems are a separate discipline rather than a library feature.
- Real-world: the assignment domains — supply chain, healthcare, finance, and insurance — each produce long, detailed customer requirements; the discipline of capturing a requirement completely (any template, or plain English) is the professional skill being trained.
- Real-world: the university schema (class_id, course_number, credit_hours, section_id, instructor_name, text, classroom, capacity, publisher) is a miniature of how real registries are modeled — functional dependencies among real attributes, candidate keys found by closure, and schemas normalized from them. The same closure-and-synthesis machinery that turned into two clean relations is what turns a real-world registry's dependency list into its normalized tables.
DDA Lecture 5 notes · Database Normalization: Closure, Minimal Cover, and the 3NF Synthesis Algorithm
Sections Breakdown
Why data management is its own discipline, the four properties of a good database (clear semantics, least redundancy and update anomalies, least null entries, least spurious tuples), the 1NF to BCNF staircase of rules, and the key vocabulary: superkey, candidate key, primary key, prime attribute.
How a functional dependency B to C means wherever B repeats, C repeats — the source of redundancy and anomalies; why 2NF, 3NF and BCNF each remove one class of dependency; and the class debate on why higher normal forms better satisfy the four properties.
Every normalization split adds a join; denormalization as a deliberate decision rule; indexes; and the NoSQL (MongoDB, Cassandra, Neo4j) trade of redundancy for retrieval speed at scale.
The closure F+ of a dependency set, Armstrong's axioms — reflexivity, augmentation, transitivity — the derived union, decomposition and pseudotransitivity rules, and the attribute closure X+ algorithm that doubles as the superkey test.
Four worked attribute closures on a university mini-world — class_id, course_number, section_id and the pair (course_number, instructor_name) — with student questions on composite left sides, candidate keys, and why closures ignore real-world beliefs.
Equivalence of dependency sets by closure equality, when a dependency or a left-side attribute is redundant, and the three-step reduction procedure with a recheck after every removal.
The full minimal-cover drill on a concrete set: splitting right-hand sides, closure-comparison tests, removing a redundant left-side attribute, the recheck that retires B → A, and the candidate key B.
The three-step recipe from minimal cover to a relational schema — one relation per dependency, plus a key relation when needed — with verification of dependency preservation, losslessness, and the resulting normal form.
The closed-book mid-semester exam patterns, the four-level answer structure expected on the open-book final, explicit study tips, and the individual assignment guidance.
Where normalization meets industry: NoSQL systems accepting redundancy for retrieval speed, denormalization as standard practice, and the university schema as a miniature of how real registries are modeled.
Exam Revision Notes
Below is the distilled, exam-ready core. Every entry comes from the full explanation above. Use this section for rapid review; return to the main notes when a point needs more context.
Why Database Systems Exist — Recap of the Four Properties of a Good Database
Must-know: The four properties of a good database design (good semantics, least redundancy and update anomalies, least null entries, least spurious tuples); the formal conditions of 2NF, 3NF and BCNF; the definitions of superkey, candidate key, primary key and prime attribute.
⚠️ Top pitfall: Using the compressed spoken 3NF rule 'alpha is a superkey and beta is a prime attribute' — the standard definition is an OR, and only one condition needs to hold.
Self-check: In a BCNF relation, what is allowed on the left-hand side of every functional dependency?
Connects to: Section 5.2 of this lecture
Functional Dependencies Create Redundancy — Why Higher Normal Forms Are Better
Must-know: A functional dependency B to C means wherever B repeats, C repeats, which is redundancy; redundancy causes uncertainty and insert/update/delete anomalies. 2NF removes partial dependencies, 3NF removes non-prime to non-prime dependencies, BCNF allows only superkey left sides. Fewer dependencies means the four properties are better satisfied.
⚠️ Top pitfall: Confusing a part of a composite candidate key with the key itself: the primary key never repeats, but a member of it can and does — and everything it determines repeats with it.
Self-check: Why does a partial dependency (a non-prime attribute depending on part of a key) cause redundancy?
Connects to: Sections 5.1, 5.3 of this lecture
The Cost of Normalization — Why Not Everything Is in BCNF
Must-know: Normalization splits add joins, so retrieval costs more; the decision rule is 3NF/BCNF when updates dominate and 2NF (or 1NF) with redundancy and indexes when retrieval dominates; BCNF decisions happen at design time, not update time; NoSQL (MongoDB, Cassandra, Neo4j) accepts redundancy for retrieval speed and replication ease.
⚠️ Top pitfall: Believing the BCNF decision is made when an update occurs — it must be made at design time, the moment the functional dependency is known.
Self-check: When should a team deliberately keep a 2NF schema instead of normalizing to 3NF?
Connects to: Sections 5.2, 5.4 of this lecture
The Closure of a Functional Dependency Set (F+)
Must-know: The three rules: reflexivity (X superset of Y implies X to Y), augmentation (X to Y implies XZ to YZ), transitivity (X to Y and Y to Z imply X to Z); the attribute closure algorithm starts with X+ = X and repeatedly adds right sides of dependencies whose left side is inside X+; X is a superkey iff X+ = R.
⚠️ Top pitfall: Applying decomposition to a composite left side: from AB to CD you may not conclude A to C — the combination acts as one unit.
Self-check: How do you test whether a set of attributes is a superkey using attribute closure?
Connects to: Sections 5.5, 5.6 of this lecture
Attribute Closure Worked in a University Schema
Must-know: How to compute an attribute closure by repeatedly firing dependencies whose left side is inside the closure; a set whose closure covers the whole relation is a candidate key; AB to CD never means A to C alone; closures use only the given dependencies, never external knowledge.
⚠️ Top pitfall: Applying real-world knowledge (a course belongs to a subject) when computing a closure — only the given functional dependencies count.
Self-check: Why is section_id a candidate key of the university relation while (course_number, instructor_name) is not?
Connects to: Sections 5.4, 5.6 of this lecture
The Minimal Cover of a Functional Dependency Set
Must-know: Two dependency sets are equivalent when their closures are equal (F+ = F'+); a dependency (or left-side attribute) is redundant when removing it leaves an equivalent set; the minimal cover procedure: split right sides into singletons, remove redundant dependencies, remove redundant left-side attributes, recheck after each removal; minimal covers need not be unique.
⚠️ Top pitfall: Not rechecking after a removal — a dependency that was not redundant can become redundant once another dependency is gone.
Self-check: How do you test whether a single attribute on the left side of a dependency is redundant?
Connects to: Sections 5.4, 5.7 of this lecture
Worked Example — Minimal Cover of {B → A, D → A, AB → D}
Must-know: The four-step minimal cover drill: split right sides into singletons, test each dependency by comparing closures with and without it, test each left-side attribute by replacing the dependency and comparing closures, then recheck the new set — a removal can make another dependency redundant (B to A became redundant after AB to D shrank to B to D).
⚠️ Top pitfall: Skipping the recheck after a removal: B to A survived step 2 but became redundant in step 4 once AB to D was replaced by B to D.
Self-check: Why did B to A pass the step-2 test but fail the step-4 recheck?
Connects to: Sections 5.6, 5.8 of this lecture
The 3NF Synthesis Algorithm
Must-know: 3NF synthesis: (1) find the minimal cover, (2) create one relation per dependency X to A containing X and A, (3) if no relation contains a candidate key, add one relation with the key attributes; the result is dependency-preserving and lossless and at least in 3NF.
⚠️ Top pitfall: Forgetting the third step: if no synthesized relation contains a candidate key, the decomposition is lossy — the key relation must be added.
Self-check: Why must at least one synthesized relation contain a candidate key?
Connects to: Sections 5.6, 5.7 of this lecture
Exam Guidance Summary
Must-know: Mid-semester (closed book, about five weeks out): theory plus practical patterns — customer specification to ER diagram, ER diagram to relational schema, functional dependencies to normal form then 3NF/BCNF conversion, creating tables. Final (open book): four-level answers — implication of the problem, solution options, which option satisfies which requirement with its cost, then a verdict.
⚠️ Top pitfall: Preparing for the closed-book exam as if it were open book: the theory (rules, definitions, algorithms) must be at your fingertips without notes.
Self-check: What are the four levels of an answer expected on the open-book final exam?
Connects to: Section 5.1 of this lecture
Key Industry Applications
Must-know: Where normalization meets industry: NoSQL (MongoDB, Cassandra, Neo4j) trades redundancy for retrieval speed and replication ease; denormalization to 2NF/1NF is a deliberate choice when maintenance cost exceeds benefit; the university schema mirrors real registries.
Self-check: Why do large NoSQL deployments deliberately keep redundancy?
Connects to: Sections 5.3 of this lecture
Was this lecture useful?
BitsNotes AI Assistant
Subject Notes AssistantConfigure AI Chat
Choose how to access the chatbotSigned in as
Powered by BitsNotes — 20 messages per day. No API key needed. Want unlimited access? Use "Bring Your Own Key" mode.
Sign in to use AI Chat
Get 20 free AI messages per day to ask questions about your lecture notes. Sign in with Google or GitHub — it takes 5 seconds.
Sign In to BitsNotesSwitch to "Bring Your Own Key" tab above for unlimited access with any OpenAI-compatible provider.