π§βπ What is ER Model?
The Entity-Relationship (ER) Model is a high-level data model used to visually describe the structure of a database by identifying:
Entities
Attributes
Relationships
It was introduced by Peter Chen in 1976.
π Purpose of ER Model:
To design a conceptual schema of a database.
To understand the real-world structure of data before implementation.
Helps bridge the gap between users and designers.
π¦ Main Components of ER Model:
Component | Description | Symbol in ER Diagram |
|---|---|---|
Entity | Real-world object (person, place, thing) | Rectangle π¦ |
Attribute | Property of an entity | Ellipse π |
Relationship | Association between entities | Diamond π· |
Primary Key | Uniquely identifies an entity | Underlined Attribute |
Weak Entity | Cannot exist without another entity | Double Rectangle β¬β¬ |
Derived Attribute | Calculated from another attribute | Dashed Ellipse |
<div class="infographic-erd-example">
<style>
.infographic-erd-example {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--line: #ddd6c9;
--prime: #c0392b;
--mono-font: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
background: var(--paper);
color: var(--ink);
padding: 2rem 1.5rem 2.5rem;
max-width: 820px;
margin: 0 auto;
box-sizing: border-box;
}
.infographic-erd-example[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #121212;
--paper-alt: #1e1e26;
--accent: #5b8def;
--accent-soft:#202942;
--line: #2c313d;
--prime: #e57373;
}
.infographic-erd-example *, .infographic-erd-example *::before, .infographic-erd-example *::after {
box-sizing: border-box;
}
.infographic-erd-example h2 {
font-size: 1.4rem;
margin: 0 0 0.25rem;
letter-spacing: -0.01em;
}
.infographic-erd-example .subtitle {
color: var(--ink-soft);
font-size: 0.92rem;
margin: 0 0 1.5rem;
max-width: 56ch;
}
.infographic-erd-example .diagram-wrap {
background: var(--paper-alt);
border-radius: 14px;
padding: 0.75rem 0.5rem 0.25rem;
margin-bottom: 1rem;
}
.infographic-erd-example svg {
width: 100%;
height: auto;
display: block;
}
.infographic-erd-example .shape {
fill: var(--paper);
stroke: var(--ink);
stroke-width: 2;
cursor: pointer;
transition: stroke 0.25s ease, stroke-width 0.25s ease, filter 0.25s ease;
}
.infographic-erd-example .shape.is-active {
stroke: var(--accent);
stroke-width: 3;
filter: drop-shadow(0 0 4px var(--accent-soft));
}
.infographic-erd-example .conn-line {
stroke: var(--ink-soft);
stroke-width: 1.6;
transition: stroke 0.25s ease, stroke-width 0.25s ease;
}
.infographic-erd-example .conn-line.is-active {
stroke: var(--accent);
stroke-width: 2.4;
}
.infographic-erd-example .node-label {
font-size: 13px;
font-weight: 700;
fill: var(--ink);
text-anchor: middle;
dominant-baseline: central;
pointer-events: none;
}
.infographic-erd-example .node-label.prime-text {
fill: var(--prime);
text-decoration: underline;
}
.infographic-erd-example .kicker-text {
font-size: 9.5px;
letter-spacing: 0.04em;
fill: var(--ink-soft);
text-anchor: middle;
text-transform: uppercase;
pointer-events: none;
}
.infographic-erd-example .node-group { cursor: pointer; }
.infographic-erd-example .info-panel {
border-radius: 12px;
border: 1px solid var(--line);
background: var(--paper);
padding: 0.85rem 1rem;
margin-bottom: 0.6rem;
}
.infographic-erd-example .info-role {
display: inline-block;
font-size: 0.66rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--accent);
background: var(--accent-soft);
padding: 0.15rem 0.55rem;
border-radius: 999px;
margin-bottom: 0.4rem;
}
.infographic-erd-example .info-name {
font-weight: 700;
font-size: 1rem;
margin: 0 0 0.25rem;
}
.infographic-erd-example .info-desc {
font-size: 0.85rem;
color: var(--ink-soft);
margin: 0;
}
.infographic-erd-example .progress-track {
height: 3px;
background: var(--line);
border-radius: 999px;
overflow: hidden;
margin-bottom: 1rem;
}
.infographic-erd-example .progress-fill {
height: 100%;
width: 0%;
background: var(--accent);
}
.infographic-erd-example .progress-fill.is-animating {
animation: erd-progress 2.4s linear forwards;
}
@keyframes erd-progress {
from { width: 0%; }
to { width: 100%; }
}
.infographic-erd-example .hint {
font-size: 0.72rem;
color: var(--ink-soft);
text-align: center;
margin: -0.6rem 0 1rem;
}
.infographic-erd-example .takeaway {
margin-top: 0.5rem;
font-size: 0.88rem;
color: var(--ink-soft);
border-left: 3px solid var(--accent);
padding: 0.5rem 0 0.5rem 0.9rem;
}
.infographic-erd-example .takeaway strong { color: var(--ink); }
@media (prefers-reduced-motion: reduce) {
.infographic-erd-example *, .infographic-erd-example *::before, .infographic-erd-example *::after {
animation-duration: 0.001ms !important;
transition-duration: 0.001ms !important;
}
}
</style>
<h2>Entity Relationship Diagram (ERD)</h2>
<p class="subtitle">A full ERD, piece by piece. It walks itself β or click any shape to jump straight to it.</p>
<div class="diagram-wrap">
<svg id="erd-svg" viewBox="0 0 700 380" xmlns="http://www.w3.org/2000/svg">
<!-- connecting lines -->
<line class="conn-line" id="ln-name-student" x1="210" y1="86" x2="225" y2="165"/>
<line class="conn-line" id="ln-email-student" x1="210" y1="294" x2="225" y2="215"/>
<line class="conn-line" id="ln-ssn-student" x1="120" y1="190" x2="170" y2="190"/>
<line class="conn-line" id="ln-student-joins" x1="280" y1="190" x2="305" y2="190"/>
<line class="conn-line" id="ln-joins-course" x1="395" y1="190" x2="420" y2="190"/>
<line class="conn-line" id="ln-cid-course" x1="580" y1="190" x2="530" y2="190"/>
<line class="conn-line" id="ln-title-course" x1="490" y1="86" x2="475" y2="165"/>
<line class="conn-line" id="ln-duration-course" x1="490" y1="294" x2="475" y2="215"/>
<!-- Name attribute -->
<g class="node-group" data-key="name">
<text class="kicker-text" x="210" y="26">Attribute</text>
<ellipse class="shape" cx="210" cy="60" rx="56" ry="26"/>
<text class="node-label" x="210" y="60">Name</text>
</g>
<!-- Title attribute -->
<g class="node-group" data-key="title">
<text class="kicker-text" x="490" y="26">Attribute</text>
<ellipse class="shape" cx="490" cy="60" rx="56" ry="26"/>
<text class="node-label" x="490" y="60">Title</text>
</g>
<!-- SSN prime attribute -->
<g class="node-group" data-key="ssn">
<text class="kicker-text" x="70" y="158">Prime Attribute</text>
<ellipse class="shape" cx="70" cy="190" rx="50" ry="24"/>
<text class="node-label prime-text" x="70" y="190">SSN</text>
</g>
<!-- CID prime attribute -->
<g class="node-group" data-key="cid">
<text class="kicker-text" x="630" y="158">Prime Attribute</text>
<ellipse class="shape" cx="630" cy="190" rx="50" ry="24"/>
<text class="node-label prime-text" x="630" y="190">CID</text>
</g>
<!-- Student entity -->
<g class="node-group" data-key="student">
<text class="kicker-text" x="225" y="153">Entity</text>
<rect class="shape" x="170" y="165" width="110" height="50" rx="2"/>
<text class="node-label" x="225" y="190">Student</text>
</g>
<!-- Course entity -->
<g class="node-group" data-key="course">
<text class="kicker-text" x="475" y="153">Entity</text>
<rect class="shape" x="420" y="165" width="110" height="50" rx="2"/>
<text class="node-label" x="475" y="190">Course</text>
</g>
<!-- Joins relationship -->
<g class="node-group" data-key="joins">
<text class="kicker-text" x="350" y="140">Relationship</text>
<polygon class="shape" points="350,158 395,190 350,222 305,190"/>
<text class="node-label" x="350" y="190">Joins</text>
</g>
<!-- Email attribute -->
<g class="node-group" data-key="email">
<ellipse class="shape" cx="210" cy="320" rx="56" ry="26"/>
<text class="node-label" x="210" y="320">Email</text>
<text class="kicker-text" x="210" y="360">Attribute</text>
</g>
<!-- Duration attribute -->
<g class="node-group" data-key="duration">
<ellipse class="shape" cx="490" cy="320" rx="56" ry="26"/>
<text class="node-label" x="490" y="320">Duration</text>
<text class="kicker-text" x="490" y="360">Attribute</text>
</g>
</svg>
</div>
<div class="progress-track"><div class="progress-fill" id="erd-progress"></div></div>
<div class="info-panel">
<span class="info-role" id="erd-role">Entity</span>
<p class="info-name" id="erd-name">Student</p>
<p class="info-desc" id="erd-desc"></p>
</div>
<div class="hint" id="erd-hint">auto-touring Β· click any shape to pause & jump there</div>
<p class="takeaway"><strong>Six shapes, one story:</strong> two entities, their attributes, and the relationship that ties them together β every ERD is this same pattern, just repeated.</p>
<script>
(function () {
var wrapper = document.currentScript.closest('.infographic-erd-example')
|| document.querySelector('.infographic-erd-example');
var bodyAttr = document.body.getAttribute('data-darkmode');
var dark;
if (bodyAttr === 'true') {
dark = true;
} else if (bodyAttr === 'false') {
dark = false;
} else {
var match = document.cookie.match(/(?:^|;\s*)darkMode=([^;]+)/);
dark = match ? match[1] === 'true' : false;
}
if (dark) wrapper.setAttribute('data-theme', 'dark');
var DATA = {
student: {
role: 'Entity', name: 'Student',
desc: 'A rectangle β the entity itself. Every attribute and relationship around it exists to describe or connect to Student.',
lines: ['ln-name-student', 'ln-email-student', 'ln-ssn-student', 'ln-student-joins']
},
ssn: {
role: 'Prime Attribute', name: 'SSN',
desc: 'Underlined in red β SSN uniquely identifies each Student. It\'s the primary key of the entity.',
lines: ['ln-ssn-student']
},
name: {
role: 'Attribute', name: 'Name',
desc: 'A regular attribute of Student β it describes the entity but can\'t uniquely identify it on its own.',
lines: ['ln-name-student']
},
email: {
role: 'Attribute', name: 'Email',
desc: 'Another attribute of Student, connected the same way as Name.',
lines: ['ln-email-student']
},
joins: {
role: 'Relationship', name: 'Joins',
desc: 'The diamond β this is what actually connects Student to Course. Without it, they\'re just two unrelated entities.',
lines: ['ln-student-joins', 'ln-joins-course']
},
course: {
role: 'Entity', name: 'Course',
desc: 'The second entity in this diagram, linked to Student only through the Joins relationship.',
lines: ['ln-title-course', 'ln-duration-course', 'ln-cid-course', 'ln-joins-course']
},
cid: {
role: 'Prime Attribute', name: 'CID',
desc: 'Course\'s primary key β uniquely identifies each Course, the same role SSN plays for Student.',
lines: ['ln-cid-course']
},
title: {
role: 'Attribute', name: 'Title',
desc: 'A regular attribute describing the Course.',
lines: ['ln-title-course']
},
duration: {
role: 'Attribute', name: 'Duration',
desc: 'Another attribute of Course, alongside Title.',
lines: ['ln-duration-course']
}
};
var order = ['student', 'ssn', 'name', 'email', 'joins', 'course', 'cid', 'title', 'duration'];
var svg = wrapper.querySelector('#erd-svg');
var groups = wrapper.querySelectorAll('.node-group');
var progress = wrapper.querySelector('#erd-progress');
var hint = wrapper.querySelector('#erd-hint');
var roleEl = wrapper.querySelector('#erd-role');
var nameEl = wrapper.querySelector('#erd-name');
var descEl = wrapper.querySelector('#erd-desc');
var reduceMotion = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
var currentIndex = 0;
var autoTimer = null;
var isPaused = false;
function setActive(key) {
var d = DATA[key];
groups.forEach(function (g) {
g.querySelector('.shape').classList.toggle('is-active', g.getAttribute('data-key') === key);
});
svg.querySelectorAll('.conn-line').forEach(function (l) { l.classList.remove('is-active'); });
d.lines.forEach(function (id) {
var l = wrapper.querySelector('#' + id);
if (l) l.classList.add('is-active');
});
roleEl.textContent = d.role;
nameEl.textContent = d.name;
descEl.textContent = d.desc;
}
function restartProgress() {
progress.classList.remove('is-animating');
void progress.offsetWidth;
if (!isPaused) progress.classList.add('is-animating');
}
function showStep(key) {
setActive(key);
restartProgress();
}
function advance() {
currentIndex = (currentIndex + 1) % order.length;
showStep(order[currentIndex]);
}
function startTour() {
if (reduceMotion) return;
clearInterval(autoTimer);
autoTimer = setInterval(advance, 2400);
progress.classList.add('is-animating');
}
function stopTour() {
clearInterval(autoTimer);
progress.classList.remove('is-animating');
}
groups.forEach(function (g) {
g.addEventListener('click', function () {
isPaused = true;
stopTour();
var key = g.getAttribute('data-key');
currentIndex = order.indexOf(key);
showStep(key);
hint.textContent = 'paused Β· showing your selection';
});
});
showStep(order[0]);
if (!reduceMotion) {
startTour();
hint.textContent = 'auto-touring Β· click any shape to pause & jump there';
} else {
hint.textContent = 'click any shape to explore';
}
})();
</script>
</div>.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!');
});π― Why ER Diagrams are Useful:
Easy to communicate with non-technical stakeholders
Acts as a blueprint for creating actual database tables
Helps in normalization and identifying redundancy
π§ Summary Table
Term | Meaning |
|---|---|
ER Model | A conceptual framework to design a database |
ER Diagram | Visual representation of entities and their relations |