Normalization is the process of organizing data in a database to eliminate redundancy and ensure data integrity.
π― Main Goals of Normalization:
Goal | Meaning |
|---|---|
β Eliminate data redundancy | Avoid storing the same data in multiple places |
β Avoid anomalies | Prevent insertion, update, and deletion anomalies |
β Maintain data integrity | Keep data accurate, consistent, and logically organized |
β Break large tables into smaller ones | Create focused, related tables connected with foreign keys |
π§ What Do We Actually Do in Normalization?
We transform a large, unstructured or poorly structured table into multiple smaller and well-structured tables by:
Identifying functional dependencies
Splitting tables based on those dependencies
Assigning keys (primary/foreign) to maintain relationships
Following specific "normal forms" (rules) β 1NF, 2NF, 3NF, etc.
π Example Before Normalization:
Student_ID | Student_Name | Course | Instructor |
|---|---|---|---|
101 | Swati | DBMS | Mr. Roy |
102 | Ravi | OS | Mrs. Khan |
103 | Swati | AI | Mr. Roy |
π΄ Problems:
Repetition of instructor names
Swati repeated
Difficult to update a course or instructor without affecting other data
β After Normalization:
π§© Student Table
Student_ID | Student_Name |
|---|---|
101 | Swati |
102 | Ravi |
π§© Instructor Table
Instructor_ID | Instructor_Name |
|---|---|
1 | Mr. Roy |
2 | Mrs. Khan |
π§© Course Table
Course | Instructor_ID |
|---|---|
DBMS | 1 |
OS | 2 |
AI | 1 |
π§© Enrollment Table
Student_ID | Course |
|---|---|
101 | DBMS |
102 | OS |
103 | AI |
π Normalization in Action:
Step | What We Do |
|---|---|
1NF | Remove repeating groups/arrays β every field must hold atomic values |
2NF | Remove partial dependencies β non-key fields depend on whole primary key |
3NF | Remove transitive dependencies β non-key attributes should not depend on other non-key attributes |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Normalization β 1NF to 3NF</title>
<style>
.infographic-normalization {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--line: #ddd6c9;
--good: #16a34a;
--good-soft: #dcfce7;
--bad: #dc2626;
--bad-soft: #fee2e2;
--warn: #b45309;
--warn-soft: #fef3c7;
--display-font: Georgia, 'Iowan Old Style', serif;
--body-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
--mono-font: 'SF Mono', Consolas, monospace;
background: var(--paper);
color: var(--ink);
font-family: var(--body-font);
max-width: 1080px;
margin: 0 auto;
box-sizing: border-box;
overflow-x: hidden;
}
.infographic-normalization[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #121212;
--paper-alt: #1e1e26;
--accent: #5b8def;
--accent-soft:#202942;
--line: #2c313d;
--good: #4ade80;
--good-soft: #123420;
--bad: #f87171;
--bad-soft: #3a1414;
--warn: #fbbf24;
--warn-soft: #3a2f0e;
}
.infographic-normalization * { box-sizing: border-box; }
.nm-head { text-align: center; margin-bottom: 0.25rem; }
.nm-head h2 {
font-family: var(--display-font);
font-size: 2rem;
margin: 0 0 0.5rem;
}
.nm-head p {
color: var(--ink-soft);
font-size: 1rem;
margin: 0 auto;
max-width: 640px;
line-height: 1.55;
}
.nm-tabs {
display: flex;
justify-content: center;
gap: 0.5rem;
margin: 1.75rem 0 0.5rem;
flex-wrap: wrap;
}
.nm-tab {
font: inherit;
font-size: 0.88rem;
background: var(--paper-alt);
border: 1px solid var(--line);
border-radius: 999px;
padding: 0.5rem 1.1rem;
cursor: pointer;
color: var(--ink-soft);
transition: border-color 0.15s, color 0.15s, background 0.15s;
}
.nm-tab:hover { border-color: var(--accent); }
.nm-tab.is-active { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); font-weight: 600; }
.nm-panel { display: none; margin-top: 1.5rem; }
.nm-panel.is-active { display: block; animation: nm-fade 0.2s ease; }
@keyframes nm-fade { from { opacity: 0; } to { opacity: 1; } }
.nm-problem, .nm-fixed {
border-radius: 8px;
padding: 0.75rem 1rem;
font-size: 0.88rem;
line-height: 1.55;
margin-bottom: 1.1rem;
}
.nm-problem { background: var(--bad-soft); color: var(--bad); }
.nm-fixed { background: var(--good-soft); color: var(--good); }
.nm-tables-row {
display: flex;
gap: 1.25rem;
flex-wrap: wrap;
}
.nm-table-block { flex: 1 1 220px; min-width: 0; }
.nm-table-name {
font-family: var(--display-font);
font-size: 0.95rem;
margin: 0 0 0.5rem;
color: var(--ink);
}
.nm-table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; min-width: 0; }
table.nm-table {
width: 100%;
min-width: 220px;
border-collapse: collapse;
background: var(--paper-alt);
border: 1px solid var(--line);
border-radius: 8px;
font-size: 0.82rem;
}
table.nm-table th, table.nm-table td {
border: 1px solid var(--line);
padding: 0.45rem 0.6rem;
text-align: left;
white-space: nowrap;
}
table.nm-table th { background: var(--accent); color: #fff; font-weight: 700; font-size: 0.7rem; }
table.nm-table td.nm-bad-cell { background: var(--bad-soft); color: var(--bad); font-weight: 600; }
table.nm-table td.nm-warn-cell { background: var(--warn-soft); color: var(--warn); font-weight: 600; }
table.nm-table td.nm-good-cell { color: var(--good); font-weight: 600; }
.nm-chips {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
justify-content: center;
margin-top: 2rem;
}
.nm-chip {
font-size: 0.75rem;
background: var(--paper-alt);
border: 1px solid var(--line);
border-radius: 999px;
padding: 0.4rem 0.85rem;
color: var(--ink-soft);
transition: background 0.2s, color 0.2s, border-color 0.2s;
}
.nm-chip.is-done { background: var(--good-soft); color: var(--good); border-color: var(--good); }
@media (prefers-reduced-motion: reduce) {
.infographic-normalization *, .infographic-normalization *::before, .infographic-normalization *::after {
transition-duration: 0.001ms !important;
animation-duration: 0.001ms !important;
}
}
</style>
</head>
<body>
<div class="infographic-normalization" id="normalization">
<div class="nm-head">
<h2>Normalization β 1NF to 3NF</h2>
<p>Normalization removes redundancy by splitting one messy table into several clean ones, step by step. Watch the same Student/Course data reshape at each stage.</p>
</div>
<div class="nm-tabs">
<button class="nm-tab" data-tab="0" type="button">0NF β Unnormalized</button>
<button class="nm-tab" data-tab="1" type="button">1NF</button>
<button class="nm-tab" data-tab="2" type="button">2NF</button>
<button class="nm-tab" data-tab="3" type="button">3NF</button>
</div>
<!-- 0NF -->
<div class="nm-panel" data-panel="0">
<div class="nm-problem">β The <code>Courses</code> column holds multiple values in one cell β not atomic. This violates the very first rule of a relation.</div>
<div class="nm-tables-row">
<div class="nm-table-block">
<p class="nm-table-name">StudentRecord (unnormalized)</p>
<div class="nm-table-scroll">
<table class="nm-table">
<thead><tr><th>StudentID</th><th>Name</th><th>Courses</th></tr></thead>
<tbody>
<tr><td>1</td><td>Alice</td><td class="nm-bad-cell">Math, Physics</td></tr>
<tr><td>2</td><td>Bob</td><td>Chemistry</td></tr>
<tr><td>3</td><td>Zara</td><td>Calculus</td></tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- 1NF -->
<div class="nm-panel" data-panel="1">
<div class="nm-fixed">βοΈ Split into one row per course β every cell is now atomic.</div>
<div class="nm-problem">β But now <code>Name</code> repeats for Alice, and course/professor info repeats too. <code>Name</code> depends only on <code>StudentID</code>, not on the full (StudentID, CourseID) key β a <b>partial dependency</b>.</div>
<div class="nm-tables-row">
<div class="nm-table-block">
<p class="nm-table-name">StudentRecord (1NF)</p>
<div class="nm-table-scroll">
<table class="nm-table">
<thead><tr><th>StudentID</th><th>Name</th><th>CourseID</th><th>CourseName</th><th>ProfName</th><th>ProfDept</th></tr></thead>
<tbody>
<tr><td>1</td><td class="nm-warn-cell">Alice</td><td>C1</td><td>Math</td><td>Dr. Smith</td><td>Mathematics</td></tr>
<tr><td>1</td><td class="nm-warn-cell">Alice</td><td>C2</td><td>Physics</td><td>Dr. Lee</td><td>Physics</td></tr>
<tr><td>2</td><td>Bob</td><td>C3</td><td>Chemistry</td><td>Dr. Roy</td><td>Chemistry</td></tr>
<tr><td>3</td><td>Zara</td><td>C4</td><td>Calculus</td><td>Dr. Smith</td><td>Mathematics</td></tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- 2NF -->
<div class="nm-panel" data-panel="2">
<div class="nm-fixed">βοΈ Split off Student and Course into their own tables β no more attribute depends on only part of the key.</div>
<div class="nm-problem">β Inside <code>Course</code>, <code>ProfDept</code> repeats ("Mathematics" twice) β because it actually depends on <code>ProfName</code>, not on <code>CourseID</code> directly. A <b>transitive dependency</b>.</div>
<div class="nm-tables-row">
<div class="nm-table-block">
<p class="nm-table-name">Student</p>
<div class="nm-table-scroll">
<table class="nm-table">
<thead><tr><th>StudentID</th><th>Name</th></tr></thead>
<tbody>
<tr><td>1</td><td>Alice</td></tr>
<tr><td>2</td><td>Bob</td></tr>
<tr><td>3</td><td>Zara</td></tr>
</tbody>
</table>
</div>
</div>
<div class="nm-table-block">
<p class="nm-table-name">Course</p>
<div class="nm-table-scroll">
<table class="nm-table">
<thead><tr><th>CourseID</th><th>CourseName</th><th>ProfName</th><th>ProfDept</th></tr></thead>
<tbody>
<tr><td>C1</td><td>Math</td><td>Dr. Smith</td><td class="nm-warn-cell">Mathematics</td></tr>
<tr><td>C2</td><td>Physics</td><td>Dr. Lee</td><td>Physics</td></tr>
<tr><td>C3</td><td>Chemistry</td><td>Dr. Roy</td><td>Chemistry</td></tr>
<tr><td>C4</td><td>Calculus</td><td>Dr. Smith</td><td class="nm-warn-cell">Mathematics</td></tr>
</tbody>
</table>
</div>
</div>
<div class="nm-table-block">
<p class="nm-table-name">Enrollment</p>
<div class="nm-table-scroll">
<table class="nm-table">
<thead><tr><th>StudentID</th><th>CourseID</th></tr></thead>
<tbody>
<tr><td>1</td><td>C1</td></tr>
<tr><td>1</td><td>C2</td></tr>
<tr><td>2</td><td>C3</td></tr>
<tr><td>3</td><td>C4</td></tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- 3NF -->
<div class="nm-panel" data-panel="3">
<div class="nm-fixed">βοΈ Split Professor out of Course. Now "Mathematics" is stored once β every non-key column depends on the key, the whole key, and nothing but the key.</div>
<div class="nm-tables-row">
<div class="nm-table-block">
<p class="nm-table-name">Student</p>
<div class="nm-table-scroll">
<table class="nm-table">
<thead><tr><th>StudentID</th><th>Name</th></tr></thead>
<tbody>
<tr><td>1</td><td>Alice</td></tr>
<tr><td>2</td><td>Bob</td></tr>
<tr><td>3</td><td>Zara</td></tr>
</tbody>
</table>
</div>
</div>
<div class="nm-table-block">
<p class="nm-table-name">Course</p>
<div class="nm-table-scroll">
<table class="nm-table">
<thead><tr><th>CourseID</th><th>CourseName</th><th>ProfName</th></tr></thead>
<tbody>
<tr><td>C1</td><td>Math</td><td>Dr. Smith</td></tr>
<tr><td>C2</td><td>Physics</td><td>Dr. Lee</td></tr>
<tr><td>C3</td><td>Chemistry</td><td>Dr. Roy</td></tr>
<tr><td>C4</td><td>Calculus</td><td>Dr. Smith</td></tr>
</tbody>
</table>
</div>
</div>
<div class="nm-table-block">
<p class="nm-table-name">Professor</p>
<div class="nm-table-scroll">
<table class="nm-table">
<thead><tr><th>ProfName</th><th>ProfDept</th></tr></thead>
<tbody>
<tr><td>Dr. Smith</td><td class="nm-good-cell">Mathematics</td></tr>
<tr><td>Dr. Lee</td><td class="nm-good-cell">Physics</td></tr>
<tr><td>Dr. Roy</td><td class="nm-good-cell">Chemistry</td></tr>
</tbody>
</table>
</div>
</div>
<div class="nm-table-block">
<p class="nm-table-name">Enrollment</p>
<div class="nm-table-scroll">
<table class="nm-table">
<thead><tr><th>StudentID</th><th>CourseID</th></tr></thead>
<tbody>
<tr><td>1</td><td>C1</td></tr>
<tr><td>1</td><td>C2</td></tr>
<tr><td>2</td><td>C3</td></tr>
<tr><td>3</td><td>C4</td></tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="nm-chips" id="nmChips">
<span class="nm-chip" data-chip="1">1NF β Atomic values</span>
<span class="nm-chip" data-chip="2">2NF β No partial dependency</span>
<span class="nm-chip" data-chip="3">3NF β No transitive dependency</span>
</div>
</div>
<script>
(function () {
const wrapper = document.getElementById('normalization');
const bodyAttr = document.body.getAttribute('data-darkmode');
let dark;
if (bodyAttr === 'true') {
dark = true;
} else if (bodyAttr === 'false') {
dark = false;
} else {
const match = document.cookie.match(/(?:^|;\s*)darkMode=([^;]+)/);
dark = match ? match[1] === 'true' : false;
}
if (dark) wrapper.setAttribute('data-theme', 'dark');
})();
(function () {
const tabs = document.querySelectorAll('.nm-tab');
const panels = document.querySelectorAll('.nm-panel');
const chips = document.querySelectorAll('.nm-chip');
function showTab(n) {
tabs.forEach(t => t.classList.toggle('is-active', t.dataset.tab === n));
panels.forEach(p => p.classList.toggle('is-active', p.dataset.panel === n));
chips.forEach(c => c.classList.toggle('is-done', Number(c.dataset.chip) <= Number(n)));
}
tabs.forEach(t => t.addEventListener('click', () => showTab(t.dataset.tab)));
showTab('0');
})();
</script>
</body>
</html>.demo {
font-family: system-ui, sans-serif;
padding: 16px;
}
.demo h1 {
color: #2563eb;
margin: 0 0 8px;
}
.demo p {
color: #4b5563;
margin: 0;
}document.querySelector('.demo h1')?.addEventListener('click', () => {
alert('Hello from live preview!');
});β Key Reasons Why Normalization is Necessary
π Eliminate Data Redundancy
Redundancy means storing the same data in multiple places.
Leads to wastage of storage and update anomalies.
πΈ Example: If a student's college name is repeated in every row, and the college name changes, you must update every record.
β»οΈ Avoid Update Anomalies
Three types of anomalies occur in unnormalized tables:
Type of Anomaly | What Happens? |
|---|---|
Update | You update data in one place but forget elsewhere. |
Insert | You cannot insert data because some fields require values that donβt yet exist. |
Delete | Deleting a record might remove useful data unintentionally. |
π Ensure Data Integrity & Consistency
By organizing data correctly, normalization enforces rules (e.g., foreign keys).
Ensures that the database reflects real-world relationships properly.
π Make Queries More Efficient
Smaller, related tables can often be queried more efficiently than one big table.
Reduces the need for scanning large volumes of duplicated data.
π Improves Data Maintenance
Changes (insert/update/delete) are easier, safer, and faster.
Maintenance becomes manageable over time as data grows.
π Improves Relationship Representation
Helps in better representation of 1:1, 1:N, and M:N relationships between entities.
Simplifies ER modeling and schema design.
π§ Quick Summary:
Aspect | Before Normalization | After Normalization |
|---|---|---|
Data Redundancy | High | Low |
Data Consistency | Prone to anomalies | Strong |
Update Complexity | Multiple places | Single place |
Table Size | Large & unstructured | Small, logical, and related |
Relationships | Implicit or unclear | Clear with foreign keys |