DBMS
📂 Functional Dependencies & Normalization
· 5 of 9
34 min read
Functional Dependencies & Third Normal Form (3NF)
A beginner-to-pro DBMS tutorial that starts with functional dependencies and quick recaps of 1NF and 2NF, then focuses on Third Normal Form: the transitive-dependency problem that survives 2NF, the insertion/update/deletion anomalies it causes, and how to decompose a table into 3NF. Built around one running Student–Department example, with animated diagrams, before/after tables, a 2NF-vs-3NF comparison, and academic vs. industry perspectives.
Section 01
The Story That Explains Third Normal Form
📖 Real World Analogy
The Office Phone Directory Disaster
Imagine a company keeps one giant spreadsheet of employees. Each row stores the
employee's name, their department, and — printed next to every single person —
the department's office room and the department head.
The Sales team has 300 people, so "Sales · Room 4B · Mr. Khan" is copied 300 times.
One Monday, Sales moves to Room 9A and Mr. Khan is replaced. Now somebody must hunt down and edit
300 identical rows. Miss even one, and the database says Sales is in two rooms at once.
Worse: a brand-new department "AI Research" is created, but no one has joined yet — so it
cannot be recorded at all, because there is no employee row to attach it to.
And if the last person in a department resigns, the room and head vanish with them.
The room and the head were never really facts about the employee.
They were facts about the department, hiding in the wrong table.
Removing that hidden indirection is exactly what Third Normal Form does.
This tutorial builds up gently — a quick look at Functional Dependencies, then
1NF and 2NF — before focusing on the real target:
Third Normal Form (3NF), the problem 2NF leaves behind, and how 3NF fixes it.
Every step uses one consistent example so the ideas connect, and we finish with the pitfalls,
a second drill, and a self-test.
Section 02
The Foundation — Functional Dependencies
Normalization is built on one idea: the functional dependency (FD).
We write X → Y and read it as
"X determines Y" — meaning if you know the value of X, the value of Y is fixed and unambiguous.
📊 Animated — What "X determines Y" Means
One StudentID always maps to exactly one StudentName — but one name might be shared by many IDs. FDs point one way.
🔑
Three Terms You Must Lock In
A candidate key is a minimal set of attributes that uniquely identifies every row.
A prime attribute is any attribute that is part of some candidate key.
A non-prime attribute is everything else. Almost every normalization rule is
phrased in terms of how non-prime attributes depend on candidate keys.
🔍 How Professionals Discover FDs in the Real World
Rules
Read the business rules. "Each instructor teaches one course" is an FD wearing plain clothes. Most dependencies are written down in policy before they're written in SQL.
People
Interview domain experts. Ask "if I know X, is Y always fixed?" — stakeholders can answer this even if they've never heard the word "dependency."
Data
Examine sample data for patterns — but only as a hint. Data can suggest an FD; only the business rule can confirm it. A 50-row sample where every manager has one office doesn't prove managers can't share.
Trap
Never declare an FD from data alone. An FD is a claim about all legal states of the table, not the rows you happen to have today. Semantics beat samples.
Section 03
Quick Recap — First Normal Form (1NF)
1NF has one job: every cell must hold a single, atomic value —
no lists, no repeating groups, no comma-separated bundles. Each row must also be unique.
❌ Violates 1NF
StudentID
Name
Courses
S1
Aarav
DBMS, OS, CN
S2
Diya
DBMS, AI
✅ In 1NF
StudentID
Name
Course
S1
Aarav
DBMS
S1
Aarav
OS
S1
Aarav
CN
S2
Diya
DBMS
S2
Diya
AI
🌱
The Takeaway
The "Courses" cell held multiple values, so we couldn't reliably search, sort, or join on it.
Splitting it into one course per row makes the data queryable.
1NF is the entry ticket — every higher normal form assumes you are already here.
Section 04
Quick Recap — Second Normal Form (2NF)
2NF attacks the partial dependency: a non-prime attribute that depends
on only part of a composite (multi-column) key, rather than the whole key.
This problem can only appear when the key is made of more than one attribute.
Take an ENROLLMENT table with composite key
{StudentID, CourseID}:
StudentID (key)
CourseID (key)
StudentName
CourseTitle
Grade
S1
C1
Aarav
DBMS
A
S1
C2
Aarav
Operating Systems
B
S2
C1
Diya
DBMS
A
⚖️ Spotting The Partial Dependencies
FD 1
StudentID → StudentName — name depends on only half the key. Partial.
FD 2
CourseID → CourseTitle — title depends on only the other half. Partial.
FD 3
{StudentID, CourseID} → Grade — grade needs the whole key. Full dependency — this one is fine.
To reach 2NF, we split each partial dependency into its own table:
👤
STUDENT
StudentID → StudentName
StudentID (key), StudentName. Each student stored once.
📚
COURSE
CourseID → CourseTitle
CourseID (key), CourseTitle. Each course stored once.
📝
ENROLLMENT
{StudentID, CourseID} → Grade
The composite key plus Grade — the only fully-dependent fact.
✅
Now in 2NF
Every non-prime attribute now depends on the whole key of its table.
We have eliminated partial dependencies. It feels finished — but a quieter, sneakier
problem can still survive. That is the bridge to 3NF.
Section 05
The Issue That 2NF Leaves Behind
Here is the crucial insight most learners miss: a table can be perfectly in 2NF and still be
badly designed. 2NF only guards against dependencies on part of the key. It says
nothing about a non-prime attribute depending on another non-prime attribute.
That hidden chain is called a transitive dependency — a non-prime attribute that
contains a fact about another non-prime attribute, instead of a fact about the key.
Take a clean STUDENT table with a single-column key
StudentID. Because the key is one attribute, partial dependency is
impossible — so this table is automatically in 2NF:
StudentID (key)
StudentName
DeptID
DeptName
DeptHead
S1
Aarav
D1
Computer Science
Dr. Rao
S2
Diya
D1
Computer Science
Dr. Rao
S3
Kabir
D2
Mathematics
Dr. Bose
S4
Mira
D1
Computer Science
Dr. Rao
Look at how the dependencies actually flow:
🔎 The Dependency Chain
Direct
StudentID → DeptID — each student belongs to one department. Good.
Hidden
DeptID → DeptName, DeptHead — a non-prime attribute determines other non-prime attributes. Transitive!
Result
StudentID → DeptID → DeptName — DeptName depends on the key only indirectly, through DeptID.
That indirection is harmless in theory but toxic in practice. It reproduces the
"Office Phone Directory Disaster" from Section 01. Watch the three classic anomalies appear:
➕
Insertion Anomaly
can't add a dept alone
A new department "Physics (D3)" exists but has no students yet.
You cannot record it — there is no StudentID to attach it to.
🔄
Update Anomaly
edit many rows
Dr. Rao is replaced as CS head. You must update
every CS student row. Miss one, and the data contradicts itself.
🗑️
Deletion Anomaly
lose facts silently
If Kabir (the only Maths student) is deleted, the existence of the
Mathematics department and Dr. Bose vanishes too.
⚠️
This Is The Whole Point
The table satisfies 2NF completely, yet it still suffers redundancy and all three anomalies.
The culprit is the transitive dependency 2NF was never designed to catch.
Third Normal Form exists specifically to remove it.
Section 06
Third Normal Form — The Definition (and Its History)
A relation is in Third Normal Form if it is already in 2NF and it contains
no transitive dependency of a non-prime attribute on a candidate key. The formal test
is a rule about every non-trivial functional dependency
X → Y in the table:
Condition A
X is a superkey
The left-hand side uniquely identifies the row (it is, or contains, a candidate key).
Condition B
Y is a prime attribute
Every attribute on the right-hand side is part of some candidate key.
📝
The Rule, In One Sentence
For each functional dependency, at least one of the two conditions must hold.
If you ever find a dependency where the left side is not a superkey
and the right side is not a prime attribute, the table breaks 3NF.
📚
A Little History Worth Knowing
3NF was defined by E. F. Codd in 1971, the father of the relational model.
The crisp two-condition test above is Carlo Zaniolo's 1982 reformulation — the
version textbooks use today, because it makes the difference between 3NF and BCNF visible at a
glance (BCNF simply deletes Condition B). And the famous mantra —
"every non-key attribute must depend on the key, the whole key, and nothing but the key" —
comes from Bill Kent's 1983 paper "A Simple Guide to Five Normal Forms," often
quoted with the playful courtroom oath appended: "…so help me Codd."
Section 07
Animated Diagram — How a Transitive Dependency Forms and Breaks
Watch the dependency pulse travel from the key, through the non-prime attribute, to the final
attribute — the indirect red path is what 3NF forbids.
🔮 Before — Transitive Dependency Inside One Table
DeptName never touches the key directly. It rides on DeptID — the textbook transitive dependency.
✅ After — Decomposition Splits the Chain
DeptName and DeptHead now live once, beside the key they truly belong to. The chain is gone.
Section 08
Worked Example — Converting the Table to 3NF
We remove the transitive dependency by lifting the offending group
(DeptID, DeptName, DeptHead) into its own table, leaving only the
foreign key DeptID behind.
❌ STUDENT (2NF, redundant)
SID
Name
DeptID
DeptName
Head
S1
Aarav
D1
Comp Sci
Rao
S2
Diya
D1
Comp Sci
Rao
S3
Kabir
D2
Maths
Bose
S4
Mira
D1
Comp Sci
Rao
✅ STUDENT (3NF, lean)
SID
Name
DeptID (FK)
S1
Aarav
D1
S2
Diya
D1
S3
Kabir
D2
S4
Mira
D1
New table: DEPARTMENT
DeptName
DeptHead
D1 (PK)
Computer Science
Dr. Rao
D2 (PK)
Mathematics
Dr. Bose
🎉 Every Anomaly Is Now Fixed
Insert
Add "Physics (D3)" to DEPARTMENT with zero students. Works.
Update
Change the CS head once, in one row of DEPARTMENT. No fan-out.
Delete
Remove the last Maths student; the Maths department survives in DEPARTMENT. Safe.
Verify
In STUDENT, the only FD is StudentID → Name, DeptID — left side is the key. In DEPARTMENT, DeptID → DeptName, DeptHead — left side is the key. Both in 3NF.
Section 09
Second Drill — The Geography Chain (a Classic Exam Pattern)
Transitive dependencies love to hide in address and geography columns. Here is the
pattern that appears in countless real schemas and exam papers — a candidate registration table:
CandNo (key)
CandName
State
Country
PinCode
C1
Aarav
Himachal Pradesh
India
173212
C2
Diya
Himachal Pradesh
India
173212
C3
Liam
California
USA
94016
🧭 Walk the Test Yourself
Spot
State → Country — Himachal Pradesh is always India. A non-prime attribute determines another non-prime attribute. Transitive via State.
Spot
PinCode → State — a postal code pins down the state too. Another hidden chain: CandNo → PinCode → State → Country. A two-link transitive chain!
Fix
Lift the geography into its own lookup: LOCATION(PinCode, State, Country), and keep only PinCode as a foreign key in CANDIDATE. Both tables now in 3NF.
Lesson
Chains can be longer than one hop. Whenever columns "travel together" (city/state/country, code/description, product/category/category-manager), suspect a transitive chain.
Section 10
2NF vs 3NF — Side by Side
Aspect
Second Normal Form
Third Normal Form
Target problem
Partial dependency
Transitive dependency
Dependency removed
Non-prime on part of the key
Non-prime on another non-prime
Needs composite key to occur?
Yes — only multi-attribute keys
No — happens even with single-column keys
Prerequisite
Must already be in 1NF
Must already be in 2NF
Rule of thumb
Depend on the whole key
Depend on nothing but the key
Remaining risk
Transitive chains still allowed
Rare overlapping-key cases → BCNF
🧠
The One-Line Mental Model
1NF = no repeating groups. 2NF = no partial dependency.
3NF = no transitive dependency. Each form removes exactly one species of
redundancy the previous one couldn't see.
Section 11
Common Pitfalls & Misconceptions
These are the mistakes that show up again and again in code reviews, exams, and interviews —
even from people who can recite the definition perfectly.
🧮
The Derived-Column Trap
TotalPrice = Qty × UnitPrice
Storing a computed column like TotalPrice alongside Qty and UnitPrice creates a
dependency on non-key attributes — a 3NF violation in disguise. Compute it in a query or
view instead, or accept it as deliberate, documented denormalization.
🔬
Judging FDs From Sample Data
semantics > samples
"In our data, every manager has one office, so Manager → Office." Maybe — or maybe the sample
is just small. An FD is a business rule about all legal states, not a pattern in
today's rows. Confirm with the domain, not the spreadsheet.
✂️
Over-Normalizing Everything
lookup-table mania
Splitting a two-value Status column ("Active"/"Inactive") into its own table adds
joins without removing any real dependency. 3NF targets transitive facts, not every
repeated string. Normalize dependencies, not vocabulary.
🔑
"Single Key = Automatic 3NF"
false comfort
A single-column key guarantees 2NF, not 3NF — our Student–Department table
proved it. Transitive chains don't care how many columns your key has.
🔗
Missing Multi-Hop Chains
A → B → C → D
People check one hop and stop. The geography drill showed a two-link chain
(PinCode → State → Country). Follow every arrow until it dead-ends; each link is its own
violation.
🎯
Forgetting Why You're Doing It
3NF is a means, not a medal
The goal is integrity: one fact, one place, no anomalies. If a decomposition makes
the schema unmaintainable for zero integrity gain, you've optimized for the certificate, not the
database.
Section 12
Academic vs Industry Perspective
🎓 Academic View
Defined formally by E. F. Codd (1971); the modern two-condition test is Zaniolo's 1982 reformulation, built on functional dependencies and candidate keys.
3NF is provably lossless and dependency-preserving — you can always decompose into 3NF without losing data or FDs (the Bernstein synthesis algorithm constructs it).
Sits in the hierarchy 1NF ⊂ 2NF ⊂ 3NF ⊂ BCNF; every BCNF table is also 3NF, but not vice-versa.
Focus is on correctness: eliminating anomalies and redundancy by theorem, not by taste.
🏭 Industry View
3NF is the default target for transactional (OLTP) systems — banking, orders, inventory — where write integrity matters most.
Beyond integrity, 3NF pays off in smaller tables, leaner indexes, and simpler maintenance — schema changes touch one table instead of many.
Teams sometimes denormalize on purpose in analytics/reporting (data warehouses, star schemas) to make reads faster — the trade-off is joins vs controlled redundancy.
Practical rule: normalize to 3NF first, then denormalize only where profiling proves a real performance need.
⚖️
Where Theory Meets the Real World
Academia proves why 3NF is safe; industry decides where to apply it.
A senior engineer designs the source-of-truth schema in 3NF, then makes a deliberate,
measured choice to denormalize copies for speed — never by accident.
Section 13
When 3NF Is Enough — and When It Isn't
✅
Most OLTP Schemas
For the vast majority of business databases, 3NF removes essentially all harmful redundancy. It is the sweet spot of safety and simplicity.
orders, users, payments
⚠️
Overlapping Candidate Keys
When a table has multiple overlapping candidate keys and a non-key determinant, 3NF can still permit redundancy. That edge case is what BCNF tightens.
go one step further → BCNF
📊
Read-Heavy Analytics
Dashboards and warehouses may deliberately denormalize below 3NF for query speed — a conscious, profiled trade, not a design failure.
star / snowflake schemas
🎯
BCNF in One Breath
BCNF is the stricter sibling: every determinant (left side of an FD) must be a superkey —
no exceptions for prime attributes. If your table has a single candidate key (like most),
reaching 3NF usually puts you in BCNF for free.
Section 14
Test Yourself — Three Interview-Style Questions
Commit to an answer for each before reading the solutions below. This is how the concept sticks.
❓
Question 1
spot the violation
ORDER(OrderID, CustomerID, CustomerCity), key = OrderID, and
CustomerID → CustomerCity. Is this in 3NF? If not, what's the fix?
❓
Question 2
true or false
"3NF primarily eliminates partial dependencies." True or false — and which normal form actually
owns that job?
❓
Question 3
the subtle one
R(A, B, C) with FDs {A, B} → C and
C → B. C is not a superkey — does the table break 3NF?
🔑 Solutions — Check Your Reasoning
A1
Not in 3NF. The chain OrderID → CustomerID → CustomerCity is transitive — CustomerCity is a fact about the customer, not the order. Fix: move City to a CUSTOMER table, keep CustomerID as the FK.
A2
False. Partial dependencies are 2NF's job. 3NF eliminates transitive dependencies. Keeping these two straight is the single most common normalization-exam slip.
A3
Still in 3NF! For C → B: C is not a superkey (Condition A fails), but B is part of candidate key {A, B} — so B is a prime attribute and Condition B saves it. (This exact pattern is why BCNF exists: BCNF would reject it.)
Section 15
Golden Rules
📝 Third Normal Form — Non-Negotiable Rules
1
Reach 2NF first. 3NF is meaningless until partial dependencies are gone.
Normalization is a ladder — never skip a rung.
2
Hunt for non-prime → non-prime dependencies. If a non-key attribute is
determined by another non-key attribute, you have a transitive dependency. That is the 3NF
violation, every time — and follow chains multiple hops, not just one.
3
Apply the test: for every FD X → Y, either X is a superkey
or Y is a prime attribute. If neither holds, decompose.
4
Decompose by lifting the dependent group into its own table, leaving the
determinant behind as a foreign key. The decomposition is lossless — a join rebuilds the original.
5
Confirm FDs with the business, never with sample data alone. A dependency is a
rule about every legal state of the table — today's rows can mislead you in both directions.
6
Watch for derived columns. A stored computed value (totals, ages, durations)
depends on non-key attributes — either drop it, move it to a view, or document it as deliberate
denormalization.
7
Remember Bill Kent's mantra: every non-key attribute depends on
the key, the whole key, and nothing but the key — so help me Codd.
8
Normalize for correctness, denormalize for measured speed. Build the
source-of-truth in 3NF; relax it only where profiling proves a real read-performance need — and if
overlapping candidate keys still leave redundancy, check BCNF.