π― What is Referential Constraints?
A Referential Integrity Constraint ensures that the relationship between two tables remains consistent. It is enforced through foreign keys, which link one tableβs column to the primary key of another table.
A Referential Integrity Constraint ensures that a value in a foreign key column must either:
Match an existing value in the referenced primary key, or
Be NULL (if allowed)
π§Ύ Example: Student & Department
π§© Department Table (Parent)
DeptID (PK) | DeptName |
|---|---|
10 | Computer Science |
20 | Mathematics |
π©βπ Student Table (Child)
StudentID (PK) | Name | DeptID (FK) |
|---|---|---|
101 | Alice | 10 |
102 | Bob | 20 |
103 | Zara | 99 β |
β
DeptID = 10and20are valid because they exist in theDepartmenttable.β
DeptID = 99violates referential integrity (no such department).
π§ͺ SQL Implementation:
CREATE TABLE Department (
DeptID INT PRIMARY KEY,
DeptName VARCHAR(50)
);
CREATE TABLE Student (
StudentID INT PRIMARY KEY,
Name VARCHAR(50),
DeptID INT,
FOREIGN KEY (DeptID) REFERENCES Department(DeptID)
);This ensures:
You cannot insert a student with a non-existing
DeptIDYou cannot delete a department if students are still linked to it (unless using ON DELETE rules)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Referential Integrity β Try It Yourself</title>
<style>
.infographic-refintegrity {
--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;
--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: 980px;
margin: 0 auto;
box-sizing: border-box;
overflow-x: hidden;
}
.infographic-refintegrity[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;
}
.infographic-refintegrity * { box-sizing: border-box; }
.ri-head { text-align: center; margin-bottom: 0.25rem; }
.ri-head h2 {
font-family: var(--display-font);
font-size: 1.9rem;
margin: 0 0 0.5rem;
}
.ri-head p {
color: var(--ink-soft);
font-size: 1rem;
margin: 0 auto;
max-width: 620px;
line-height: 1.55;
}
.ri-frames {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1.5rem;
margin-top: 2rem;
min-width: 0;
}
@media (max-width: 720px) { .ri-frames { grid-template-columns: 1fr; } }
.ri-frame {
background: var(--paper-alt);
border: 1px solid var(--line);
border-radius: 10px;
padding: 1.1rem;
min-width: 0;
}
.ri-frame-title {
font-family: var(--display-font);
font-size: 1.02rem;
margin: 0 0 0.75rem;
}
.ri-table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; min-width: 0; }
table.ri-table {
width: 100%;
min-width: 260px;
border-collapse: collapse;
background: var(--paper);
border-radius: 8px;
font-size: 0.85rem;
}
table.ri-table th, table.ri-table td {
border: 1px solid var(--line);
padding: 0.5rem 0.6rem;
text-align: left;
white-space: nowrap;
}
table.ri-table th { background: var(--accent); color: #fff; font-weight: 700; font-size: 0.75rem; }
table.ri-table td.ri-fk-valid { color: var(--good); font-weight: 600; }
table.ri-table td.ri-fk-invalid { color: var(--bad); font-weight: 600; }
table.ri-table tbody tr.is-clickable { cursor: pointer; }
table.ri-table tbody tr.is-linked td { background: var(--accent-soft); }
table.ri-table tbody tr.is-broken td { background: var(--bad-soft); }
table.ri-table tr.is-new td { animation: ri-row-in 0.5s ease; }
@keyframes ri-row-in { from { background: var(--good-soft); } to { background: transparent; } }
.ri-fix-row td { background: var(--paper) !important; padding: 0.6rem !important; }
.ri-fix-note { font-size: 0.76rem; color: var(--ink-soft); margin-bottom: 0.4rem; }
.ri-fix-btns { display: flex; gap: 0.4rem; flex-wrap: wrap; }
.ri-fix-btn {
font: inherit;
font-size: 0.76rem;
background: var(--accent);
color: #fff;
border: none;
border-radius: 6px;
padding: 0.35rem 0.7rem;
cursor: pointer;
}
.ri-fix-btn:hover { opacity: 0.9; }
.ri-mini-form { display: flex; gap: 0.4rem; flex-wrap: wrap; margin-top: 0.85rem; }
.ri-mini-form input {
flex: 1 1 70px;
min-width: 0;
font: inherit;
font-size: 0.82rem;
padding: 0.4rem 0.5rem;
border: 1px solid var(--line);
border-radius: 6px;
background: var(--paper);
color: var(--ink);
}
.ri-mini-form input:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.ri-add-btn {
font: inherit;
font-size: 0.82rem;
background: var(--accent);
color: #fff;
border: none;
border-radius: 6px;
padding: 0.45rem 0.9rem;
cursor: pointer;
flex-shrink: 0;
}
.ri-add-btn:hover { opacity: 0.9; }
.ri-msg {
margin-top: 1.25rem;
padding: 0.7rem 0.9rem;
border-radius: 8px;
font-size: 0.85rem;
line-height: 1.55;
display: none;
}
.ri-msg.is-visible { display: block; }
.ri-msg.msg-bad { background: var(--bad-soft); color: var(--bad); }
.ri-msg.msg-good { background: var(--good-soft); color: var(--good); }
@media (prefers-reduced-motion: reduce) {
.infographic-refintegrity *, .infographic-refintegrity *::before, .infographic-refintegrity *::after {
transition-duration: 0.001ms !important;
animation-duration: 0.001ms !important;
}
}
</style>
</head>
<body>
<div class="infographic-refintegrity" id="refintegrity">
<div class="ri-head">
<h2>Referential Integrity β Try It Yourself</h2>
</div>
<div class="ri-frames">
<div class="ri-frame">
<p class="ri-frame-title">π§© Department (Parent)</p>
<div class="ri-table-scroll">
<table class="ri-table" id="riDeptTable"></table>
</div>
<div class="ri-mini-form">
<input id="riDeptId" type="text" placeholder="DeptID">
<input id="riDeptName" type="text" placeholder="DeptName">
<button class="ri-add-btn" id="riAddDept" type="button">Add</button>
</div>
</div>
<div class="ri-frame">
<p class="ri-frame-title">π Student (Child)</p>
<div class="ri-table-scroll">
<table class="ri-table" id="riStuTable"></table>
</div>
<div class="ri-mini-form">
<input id="riStuId" type="text" placeholder="StudentID">
<input id="riStuName" type="text" placeholder="Name">
<input id="riStuDept" type="text" placeholder="DeptID">
<button class="ri-add-btn" id="riAddStu" type="button">Add</button>
</div>
</div>
</div>
<div class="ri-msg" id="riMsg"></div>
</div>
<script>
(function () {
const wrapper = document.getElementById('refintegrity');
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 () {
let departments = [
{ id: '10', name: 'Computer Science' },
{ id: '20', name: 'Mathematics' }
];
let students = [
{ id: '101', name: 'Alice', deptId: '10' },
{ id: '102', name: 'Bob', deptId: '20' },
{ id: '103', name: 'Zara', deptId: '99' }
];
let lastNewDept = -1;
let lastNewStudent = -1;
let selectedStudent = null;
let showFixFor = '103';
const deptTable = document.getElementById('riDeptTable');
const stuTable = document.getElementById('riStuTable');
const msg = document.getElementById('riMsg');
function showMsg(text, type) {
msg.textContent = text;
msg.className = 'ri-msg is-visible msg-' + type;
msg.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
function deptExists(id) { return departments.some(d => d.id === id); }
function renderDept() {
let html = '<thead><tr><th>DeptID (PK)</th><th>DeptName</th></tr></thead><tbody>';
departments.forEach((d, i) => {
const linked = selectedStudent && selectedStudent.deptId === d.id;
html += '<tr' + (linked ? ' class="is-linked"' : '') + (i === lastNewDept ? ' class="is-new"' : '') + '>' +
'<td>' + d.id + '</td><td>' + d.name + '</td></tr>';
});
html += '</tbody>';
deptTable.innerHTML = html;
}
function renderStudent() {
let html = '<thead><tr><th>StudentID (PK)</th><th>Name</th><th>DeptID (FK)</th></tr></thead><tbody>';
students.forEach((s, i) => {
const valid = deptExists(s.deptId);
const isSel = selectedStudent && selectedStudent.id === s.id;
const rowCls = [];
if (!valid) rowCls.push('is-broken');
if (i === lastNewStudent) rowCls.push('is-new');
const fkCell = valid
? '<td class="ri-fk-valid">' + s.deptId + ' β</td>'
: '<td class="ri-fk-invalid">' + s.deptId + ' β</td>';
html += '<tr class="is-clickable' + (rowCls.length ? ' ' + rowCls.join(' ') : '') + '" data-stu="' + s.id + '">' +
'<td>' + s.id + '</td><td>' + s.name + '</td>' + fkCell + '</tr>';
if (!valid && showFixFor === s.id) {
const validIds = departments.map(d => d.id);
html += '<tr class="ri-fix-row"><td colspan="3">' +
'<div class="ri-fix-note">DeptID ' + s.deptId + ' doesn\u2019t exist. Fix it by pointing to a real department:</div>' +
'<div class="ri-fix-btns">' +
validIds.map(id => {
const d = departments.find(dep => dep.id === id);
return '<button class="ri-fix-btn" data-fix="' + s.id + '" data-newdept="' + id + '">Point to ' + id + ' (' + d.name + ')</button>';
}).join('') +
'</div></td></tr>';
}
});
html += '</tbody>';
stuTable.innerHTML = html;
stuTable.querySelectorAll('[data-stu]').forEach(row => {
row.addEventListener('click', (e) => {
if (e.target.closest('[data-fix]')) return;
const id = row.dataset.stu;
const s = students.find(st => st.id === id);
if (!deptExists(s.deptId)) {
showFixFor = (showFixFor === id) ? null : id;
renderStudent();
return;
}
selectedStudent = (selectedStudent && selectedStudent.id === id) ? null : s;
renderDept();
renderStudent();
if (selectedStudent) {
const dept = departments.find(d => d.id === selectedStudent.deptId);
showMsg('π Student "' + selectedStudent.name + '" (DeptID ' + selectedStudent.deptId + ') correctly points to Department "' + dept.name + '".', 'good');
}
});
});
stuTable.querySelectorAll('[data-fix]').forEach(btn => {
btn.addEventListener('click', (e) => {
e.stopPropagation();
const sid = btn.dataset.fix;
const newDept = btn.dataset.newdept;
const s = students.find(st => st.id === sid);
s.deptId = newDept;
showFixFor = null;
renderDept();
renderStudent();
showMsg('βοΈ Fixed! "' + s.name + '" now points to DeptID ' + newDept + ', which actually exists β referential integrity restored.', 'good');
});
});
}
document.getElementById('riAddDept').addEventListener('click', () => {
const id = document.getElementById('riDeptId').value.trim();
const name = document.getElementById('riDeptName').value.trim();
if (!id) { showMsg('β DeptID can\u2019t be empty.', 'bad'); return; }
if (deptExists(id)) { showMsg('β DeptID ' + id + ' already exists.', 'bad'); return; }
departments.push({ id, name: name || '' });
lastNewDept = departments.length - 1;
renderDept();
const wasBroken = students.some(s => s.deptId === id);
renderStudent();
if (wasBroken) {
showMsg('βοΈ Department ' + id + ' added β that also fixes any student who was already pointing to it! Referential integrity restored the other way.', 'good');
} else {
showMsg('βοΈ Department ' + id + ' added.', 'good');
}
document.getElementById('riDeptId').value = '';
document.getElementById('riDeptName').value = '';
});
document.getElementById('riAddStu').addEventListener('click', () => {
const id = document.getElementById('riStuId').value.trim();
const name = document.getElementById('riStuName').value.trim();
const deptId = document.getElementById('riStuDept').value.trim();
if (!id) { showMsg('β StudentID can\u2019t be empty.', 'bad'); return; }
if (students.some(s => s.id === id)) { showMsg('β StudentID ' + id + ' already exists.', 'bad'); return; }
if (!deptId) { showMsg('β DeptID can\u2019t be empty here.', 'bad'); return; }
if (!deptExists(deptId)) {
showMsg('β DeptID ' + deptId + ' doesn\u2019t exist in Department β this insert violates referential integrity and would be rejected.', 'bad');
return;
}
students.push({ id, name, deptId });
lastNewStudent = students.length - 1;
renderStudent();
renderDept();
showMsg('βοΈ Student ' + id + ' added, correctly referencing Department ' + deptId + '.', 'good');
document.getElementById('riStuId').value = '';
document.getElementById('riStuName').value = '';
document.getElementById('riStuDept').value = '';
});
renderDept();
renderStudent();
showMsg('β DeptID = 99 for Zara violates referential integrity β no such department exists. Click her row to fix it.', 'bad');
})();
</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!');
});π― Purpose of Referential Constraints:
Maintains logical relationships between tables
Prevents orphan records
Ensures data integrity across tables
β Summary:
Feature | Description |
|---|---|
π Based on | Foreign Key β Primary Key relationship |
π§© Maintains | Consistency between related tables |
π« Prevents | Orphaned records (unmatched foreign keys) |
π§ͺ Enforced Using |
|