Functional Dependencies & Normalization
A derivation-first guide to functional and multivalued dependencies, attribute closure, candidate keys, minimal covers, 3NF/BCNF/4NF, and decompositions that are lossless and—when possible—dependency-preserving.
Normalization is not a ritual of splitting wide tables, and “no duplicate values” is not its objective. It starts from semantic rules—dependencies saying which facts determine which other facts—and derives schemas in which each independently changing fact has one stable home. A good decomposition must also preserve information: joining the pieces must reconstruct exactly the legal original relation, without missing or spurious tuples.
The hard part is not memorizing 1NF, 2NF, 3NF, and BCNF. It is learning to move from domain statements to dependencies, use inference to find keys, and judge the two properties that a decomposition can trade off: lossless join and dependency preservation.
From domain rules to functional dependencies #
Let be a relation schema over attribute set , and let . A functional dependency (FD)
holds on relation value when any two tuples that agree on every attribute of also agree on every attribute of :
The dependency is a constraint on all legal states, not a correlation in today's rows and not necessarily a causal claim.
The reverse dependencies do not automatically hold. Many courses may share an instructor, and many instructors may share an office. Direction is the entire point.
Trivial and nontrivial dependencies #
is trivial when ; agreement on already includes agreement on . Otherwise it is nontrivial. Trivial FDs are always true and impose no additional restriction on legal instances.
A data sample can refute but not establish an FD #
If two observed tuples have the same course_id and different
instructor_id, the sample refutes course_id → instructor_id. If no such pair
exists, the sample is merely consistent with the FD. Only the domain rule says
whether every future legal state must satisfy it.
Armstrong's axioms: the inference kernel #
For a set of FDs , denotes every FD logically implied by . Armstrong's three inference rules are sound—every derived dependency is truly implied—and complete—every implied FD can be derived.
| Rule | Form | Why it is sound |
|---|---|---|
| Reflexivity | If , then | Agreement on all of includes agreement on its subset |
| Augmentation | If , then | Tuples agreeing on agree on , hence , and already agree on |
| Transitivity | If and , then | Agreement propagates through the two constraints |
Useful derived rules include:
- union: and imply ;
- decomposition: implies and ;
- pseudotransitivity: and imply .
These are proof rules, not commands that inspect stored rows.
Attribute closure turns inference into an algorithm #
The closure is the set of every attribute functionally determined by under . Compute it by a fixed point:
closure := X
repeat
for each dependency L → R in F
if L ⊆ closure then closure := closure ∪ R
until closure no longer changes
Because the universe has finitely many attributes and closure only grows, the procedure terminates.
Worked closure and key derivation #
Consider
with
Start from {student, course}:
| Step | Rule that fires | Closure |
|---|---|---|
| 0 | seed | {student, course} |
| 1 | student course → grade |
add grade |
| 2 | course → instructor |
add instructor |
| 3 | instructor → office |
add office |
| 4 | fixed point | all five attributes |
Thus {student, course} is a superkey. It is minimal because neither
{student} nor {course} closes to all attributes, so it is a candidate key.
Closure answers several questions with the same mechanism:
- Is a superkey? Exactly when .
- Does imply ? Exactly when .
- Is an attribute extraneous in a determinant? Remove it and test the closure.
- Which attributes must occur in every key? Any attribute appearing on no dependency's right side cannot be derived from others and must be seeded.
Minimal covers remove redundant syntax #
A minimal (or canonical) cover is an equivalent FD set arranged for synthesis. A common form requires:
- one attribute on each right-hand side;
- no extraneous attribute on any left-hand side;
- no dependency removable without changing the closure.
The safe workflow is:
- decompose into and ;
- for each , test whether already contains the right side; if yes, remove ;
- temporarily remove each FD and test whether the remaining set still implies it; if yes, discard the redundant FD;
- optionally regroup dependencies with equal left sides for presentation.
Order can lead to different-looking minimal covers, but they are equivalent if their closures are the same. Minimal cover does not mean a globally unique string representation.
Why the unnormalized relation is fragile #
In Enrollment, three distinct facts are mixed in one tuple:
- a student receives a grade in a course;
- a course has a responsible instructor;
- an instructor occupies an office.
That creates anomalies:
| Operation | Failure mechanism |
|---|---|
| Update | Moving one instructor requires changing every enrollment row for that instructor; a partial update contradicts instructor → office |
| Insert | A new course and instructor cannot be recorded before the first student enrolls without inventing a student/grade or accepting nulls |
| Delete | Deleting the final enrollment in a course can erase the only stored fact about the course's instructor |
The repeated strings are a symptom. The mechanism is that facts with different determinants and lifecycles occupy the same relation.
flowchart TD D["Domain rules"] --> F["Functional dependencies"] F --> C["Closures and candidate keys"] C --> M["Minimal cover"] M --> S["3NF synthesis or BCNF decomposition"] S --> L["Lossless-join test"] S --> P["Dependency-preservation test"] L --> E["SQL constraints"] P --> E
Normal forms are predicates on dependencies #
Let an attribute be prime if it belongs to at least one candidate key; otherwise it is non-prime. Normal forms are properties of a schema together with its intended dependency set—not visual properties of a table.
First normal form: one value per attribute position #
In the classical relational model, every tuple component is a single value from the declared domain; there are no repeating column groups or relation-valued cells inside the same flat relation. “Atomic” is relative to the chosen domain: a timestamp can be one value even though it has components, while a comma- separated list of product IDs is usually hiding a separate relationship.
Modern SQL systems permit arrays, JSON, and composite values. Using them is not automatically wrong; it means the nested structure and its constraints are now inside one domain value rather than represented by ordinary relations. Ask whether the application must independently identify, constrain, join, or update the elements.
Second normal form: no partial dependency on a candidate key #
A schema is in 2NF when it is in 1NF and no non-prime attribute depends on a proper subset of a candidate key. This matters only when a candidate key is composite.
Enrollment violates 2NF because candidate key (student,course) has proper
subset course, and
Both instructor and office are non-prime attributes determined without the
whole key.
Third normal form: allow only a controlled prime-attribute exception #
A schema is in 3NF when, for every nontrivial implied dependency , at least one condition holds:
- is a superkey; or
- is prime.
This definition—not the slogan “no transitive dependencies”—handles multiple candidate keys correctly. The prime-attribute exception is what lets 3NF synthesis preserve every FD while still removing the harmful non-prime dependencies.
Boyce–Codd normal form: every determinant is a superkey #
A schema is in BCNF when every nontrivial implied dependency has a superkey determinant . BCNF removes the 3NF prime-attribute exception and is therefore strictly stronger.
Every BCNF schema is in 3NF; not every 3NF schema is in BCNF.
Fourth normal form: independent multivalued facts separate #
A multivalued dependency says that, for each fixed , the set of possible values is independent of the remaining attributes . If a person can have several skills and several languages, and those facts are independent, then
Storing PersonSkillLanguage(person, skill, language) forces every skill to be
paired with every language. Two skills and three languages require six tuples;
adding one language requires two more tuples even though no skill fact changed.
4NF requires every nontrivial MVD determinant to be a superkey. Decompose into
and
The original cross-product is recovered by join, while each independent fact is stored once.
Lossless join: decomposition must not invent facts #
Suppose is decomposed into and . Projection always satisfies
because every original tuple can be reconstructed from its own projections. The danger is the reverse inclusion: projections from different tuples may recombine into spurious tuples.
For a binary FD-based decomposition, the join is lossless with respect to when implies at least one of:
The shared attributes must determine all attributes of at least one component.
For decompositions into more than two relations, use the chase/tableau test or a synthesis theorem; pairwise intuition alone is not sufficient.
Dependency preservation: can constraints be checked locally? #
A decomposition preserves dependencies when the union of the FDs projected onto each component implies all of :
If not, an original invariant may require joining relations merely to validate an insert or update. That is logically possible but operationally awkward and often not expressible by ordinary SQL keys/checks.
Losslessness and dependency preservation answer different questions:
| Property | Prevents | If absent |
|---|---|---|
| Lossless join | information loss and spurious reconstructed tuples | the decomposition changes the represented facts |
| Dependency preservation | cross-relation enforcement of original FDs | some invariants require joins, assertions, or application logic |
Never accept a lossy decomposition. Dependency preservation is a design tradeoff when stronger normal forms make it impossible.
3NF synthesis: preserve dependencies constructively #
Given a minimal cover :
- create a relation schema for each dependency in (or group equal determinants);
- remove any schema contained wholly in another;
- if no created schema contains a candidate key of the original relation, add one relation containing such a key.
The result is in 3NF, preserves the dependencies, and is lossless when the key relation condition is satisfied by the standard synthesis construction.
For Enrollment, the minimal cover is already
Synthesis produces:
EnrollmentGrade(student, course, grade)
CourseInstructor(course, instructor)
InstructorOffice(instructor, office)
EnrollmentGrade contains the original candidate key (student,course). Each
FD can be enforced in one relation, and the three fact types now have separate
lifecycles. In this example the components also satisfy BCNF because every
nontrivial determinant is a key of its component.
BCNF decomposition and its tradeoff #
If schema violates BCNF through nontrivial where is not a superkey, decompose into
and
The decomposition is lossless because the intersection contains , which determines . Repeat until no component violates BCNF.
BCNF decomposition does not guarantee dependency preservation. Consider
Candidate keys are AB and AC; therefore every attribute is prime. The schema
is in 3NF, but C → B violates BCNF because C is not a superkey. Decomposing
on that FD gives R1(C,B) and R2(A,C). The join is lossless, yet no component
contains A, B, and C together, so AB → C cannot be checked from a single
component's dependencies. Enforcing it requires a join or a stronger mechanism.
That is the real 3NF-versus-BCNF decision: retain a controlled 3NF dependency so all constraints remain local, or choose BCNF and accept cross-relation enforcement.
SQL constraints are the executable boundary #
For the synthesized enrollment schema:
CREATE TABLE instructor_office (
instructor_id bigint PRIMARY KEY,
office text NOT NULL
);
CREATE TABLE course_instructor (
course_id bigint PRIMARY KEY,
instructor_id bigint NOT NULL
REFERENCES instructor_office (instructor_id)
);
CREATE TABLE enrollment_grade (
student_id bigint NOT NULL,
course_id bigint NOT NULL
REFERENCES course_instructor (course_id),
grade numeric NOT NULL CHECK (grade BETWEEN 0 AND 100),
PRIMARY KEY (student_id, course_id)
);The key on course_instructor.course_id enforces
course → instructor. The key on instructor_office.instructor_id enforces
instructor → office. The composite key on enrollment_grade enforces one
grade per student/course pair.
SQL has no general FUNCTIONAL DEPENDENCY declaration. A dependency is locally
enforceable when its determinant is represented by a PRIMARY KEY or suitable
UNIQUE constraint in the relation that stores the determined attributes.
That is why dependency preservation has operational value.
A disciplined normalization workflow #
- Define one tuple's fact. Include time scope and units.
- List domain dependencies. Phrase each as “for one , there is exactly one .” Separate rules from observations.
- Split right-hand sides and compute a minimal cover.
- Compute closures to enumerate candidate keys and prime attributes.
- Classify violations using the formal 3NF/BCNF/4NF definitions.
- Synthesize 3NF when local enforcement is the priority, or decompose to BCNF/4NF when stronger redundancy removal is required.
- Prove losslessness. Use the binary intersection condition or a chase.
- Test dependency preservation. Identify any invariant that crosses components.
- Map every retained invariant to enforcement. Key, foreign key, check, exclusion constraint, trigger, transaction, or explicit application rule.
- Test representative updates, not just reads: insert an entity before a relationship exists, change one determining fact, and delete the last referencing tuple.
When denormalization is legitimate #
Denormalization is a physical or derived-data decision made after the normalized facts and their invariants are understood. A cached total, materialized view, search document, or event projection can be worthwhile, but it creates a second representation that needs an explicit maintenance protocol:
- which copy is authoritative;
- which transaction or asynchronous process updates the derived copy;
- what lag is allowed;
- how drift is detected and repaired;
- what readers observe during partial failure.
Calling an accidental mixed-fact table “denormalized for performance” does not answer any of those questions.
Common wrong turns #
| Mistake | Why it fails | Better question |
|---|---|---|
| Infer FDs from unique sample values | Future legal states may violate the pattern | What domain rule makes the dependency invariant? |
| Treat a surrogate key as proof of BCNF | id → all does not remove other determinants |
Which nontrivial FDs hold besides the surrogate key? |
| Memorize “3NF removes transitive dependencies” | It mishandles multiple candidate keys and prime attributes | For every implied , is a superkey or prime? |
| Decompose wherever values repeat | Repetition can be legitimate; arbitrary projection can be lossy | Which dependency or MVD identifies an independent fact? |
| Check only that the join returns current rows | One sample cannot prove losslessness | Does the dependency set satisfy the lossless-join condition? |
| Pursue BCNF without checking preservation | Important constraints can become cross-table | Which original FDs remain locally enforceable? |
| Store comma-separated IDs to “avoid joins” | Identity, references, and element updates disappear inside a string | Is this one domain value or a hidden relation? |
Exercises #
- For and , compute
and decide whether
Ais a candidate key. - In with , verify both candidate keys and explain why the schema is 3NF but not BCNF.
- For a binary decomposition and , state the FD condition that makes the join lossless.
- A person can independently hold many certifications and speak many languages. Identify the MVDs and a 4NF decomposition.
Solutions
- Seed
{A}; addBviaA→B, thenCviaB→C. NowAC→Dfires, so . The empty set does not determine all attributes, soAis a candidate key. (AB)+and(AC)+both reach all attributes; removing either attribute from each set fails, soABandACare candidate keys.C→Bhas a non-superkey determinant, violating BCNF, butBis prime, satisfying the 3NF exception.- The intersection is
{B}. The decomposition is lossless if impliesB→AB(equivalentlyB→A) orB→BC(equivalentlyB→C). person ↠ certificationandperson ↠ language. Decompose intoPersonCertification(person,certification)andPersonLanguage(person,language).
Sources
- paperDependency Structures of Data Base Relationships (Armstrong, 1974)
- paperSynthesizing Third Normal Form Relations from Functional Dependencies (Bernstein, 1976)
- paperMultivalued Dependencies and a New Normal Form for Relational Databases (Fagin, 1977)
- paperNormalized Data Base Structure: A Brief Tutorial (Codd, 1971)
- docsPostgreSQL 18 — Constraints