A view is a virtual table based on a SELECT query.
It doesn’t store data itself, but pulls it dynamically from the original table(s).
Think of it like a saved query you can use like a table!
🧠 Why Use Views?
✅ Simplify complex queries
✅ Enhance data security (hide sensitive columns)
✅ Reuse logic without repeating long queries
✅ Act like a layer between users and raw tables
📌 Example: Create a View for High-Scoring Students
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SQL Views — Try It Yourself</title>
<style>
.infographic-viewrunner {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--line: #ddd6c9;
--good: #16a34a;
--good-soft: #dcfce7;
--on-accent: #ffffff;
--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: 780px;
margin: 0 auto;
box-sizing: border-box;
overflow-x: hidden;
}
.infographic-viewrunner[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;
--on-accent: #101418;
}
.infographic-viewrunner * { box-sizing: border-box; }
.vw-topbar { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.75rem; gap: 0.5rem; flex-wrap: wrap; }
.vw-progress { font-size: 0.78rem; color: var(--ink-soft); }
.vw-showfull-btn {
font: inherit; font-size: 0.78rem; background: none; border: 1px solid var(--line);
border-radius: 999px; padding: 0.35rem 0.8rem; cursor: pointer; color: var(--ink-soft);
}
.vw-showfull-btn:hover { border-color: var(--accent); color: var(--accent); }
.vw-showfull-btn.is-on { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); }
.vw-fullcode-panel { display: none; margin-bottom: 1.25rem; }
.vw-fullcode-panel.is-visible { display: block; }
.vw-fullcode-scroll { overflow-x: auto; }
.vw-fullcode {
background: var(--ink); color: #d4e2ff; border-radius: 8px; padding: 1rem 1.2rem;
font-family: var(--mono-font); font-size: 0.72rem; line-height: 1.7; white-space: pre; opacity: 0.85;
display: inline-block;
min-width: 100%;
}
.infographic-viewrunner[data-theme="dark"] .vw-fullcode { background: #05070a; }
.vw-frame { background: var(--paper-alt); border: 1px solid var(--line); border-radius: 10px; padding: 1.25rem; }
.vw-kw { color: #9cc5ff; } .vw-str { color: #f8d980; } .vw-num { color: #4ade80; } .vw-cm { color: #7c8aa8; }
.vw-source-label { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--ink-soft); margin: 0 0 0.6rem; }
.vw-table-name { font-size: 0.7rem; color: var(--ink-soft); text-transform: uppercase; letter-spacing: 0.04em; margin: 0.4rem 0 0.2rem; }
.vw-table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; min-width: 0; margin-bottom: 0.6rem; }
table.vw-mini-table {
width: 100%; min-width: 220px; border-collapse: collapse; background: var(--paper);
border-radius: 7px; font-size: 0.85rem;
}
table.vw-mini-table th, table.vw-mini-table td {
border: 1px solid var(--line); padding: 0.45rem 0.6rem; text-align: left; white-space: nowrap;
transition: background 0.4s, color 0.4s;
}
table.vw-mini-table th { background: var(--accent); color: var(--on-accent); font-weight: 700; font-size: 0.7rem; }
table.vw-mini-table tr.is-new td { animation: vw-row-in 0.6s ease; }
@keyframes vw-row-in { from { background: var(--good-soft); } to { background: transparent; } }
table.vw-mini-table tr.is-qualifies td { color: var(--good); font-weight: 700; }
.vw-step { display: none; margin-bottom: 1rem; }
.vw-step.is-revealed { display: block; animation: vw-step-in 0.4s ease; }
@keyframes vw-step-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }
.vw-step.is-done .vw-step-code-full { display: none; }
.vw-step.is-done .vw-step-done-pill { display: flex; }
.vw-step-done-pill {
display: none; align-items: center; gap: 0.5rem; background: var(--good-soft); color: var(--good);
border-radius: 7px; padding: 0.55rem 0.85rem; font-family: var(--mono-font); font-size: 0.78rem; cursor: pointer;
}
.vw-step-done-pill .chevron { margin-left: auto; font-size: 0.7rem; opacity: 0.7; }
.vw-step.is-expanded-done .vw-step-code-full { display: block; }
.vw-step.is-expanded-done .vw-step-done-pill { background: var(--accent-soft); color: var(--accent); }
.vw-step-label { font-family: var(--display-font); font-size: 1.02rem; margin: 0 0 0.5rem; }
.vw-step-desc { font-size: 0.82rem; color: var(--ink-soft); margin: 0 0 0.7rem; line-height: 1.45; }
.vw-code-scroll { overflow-x: auto; }
.vw-code {
background: var(--ink); color: #d4e2ff; border-radius: 8px; padding: 0.8rem 1rem;
font-family: var(--mono-font); font-size: 0.78rem; line-height: 1.6; white-space: pre;
display: inline-block;
min-width: 100%;
}
.infographic-viewrunner[data-theme="dark"] .vw-code { background: #05070a; }
.vw-run-row { display: flex; justify-content: center; margin-top: 0.85rem; }
.vw-run-btn {
font: inherit; font-size: 0.85rem; background: var(--accent); color: var(--on-accent);
border: none; border-radius: 7px; padding: 0.55rem 1.1rem; cursor: pointer;
}
.vw-run-btn:hover { opacity: 0.9; }
.vw-run-btn:disabled { opacity: 0.55; cursor: wait; }
.vw-run-btn.is-secondary { background: var(--paper); color: var(--ink); border: 1px solid var(--line); }
.vw-view-def {
margin-top: 0.85rem; padding: 0.7rem 0.9rem; border-radius: 8px; border: 2px dashed var(--accent);
background: var(--accent-soft); color: var(--accent); font-family: var(--mono-font); font-size: 0.78rem;
line-height: 1.5; display: none;
}
.vw-view-def.is-visible { display: block; }
.vw-status {
text-align: center; font-size: 0.82rem; margin-top: 0.85rem; padding: 0.5rem 0.8rem;
border-radius: 7px; display: none; background: var(--good-soft); color: var(--good);
}
.vw-status.is-visible { display: block; animation: vw-step-in 0.3s ease; }
.vw-reset-row { display: flex; justify-content: center; margin-top: 1.25rem; }
@media (prefers-reduced-motion: reduce) {
.infographic-viewrunner *, .infographic-viewrunner *::before, .infographic-viewrunner *::after {
transition-duration: 0.001ms !important; animation-duration: 0.001ms !important;
}
}
</style>
</head>
<body>
<div class="infographic-viewrunner" id="viewrunner">
<div class="vw-topbar">
<span class="vw-progress" id="vwProgress"></span>
<button class="vw-showfull-btn" id="vwShowFullBtn" type="button">👁️ Show full SQL script</button>
</div>
<div class="vw-fullcode-panel" id="vwFullCodePanel">
<div class="vw-fullcode-scroll">
<div class="vw-fullcode" id="vwFullCodeContent"></div>
</div>
</div>
<div class="vw-frame">
<div id="vwSourceWrap" style="display:none;">
<p class="vw-source-label">Table: students</p>
<div class="vw-table-scroll"><table class="vw-mini-table" id="vwStudentsTable"><thead><tr><th>id</th><th>name</th><th>marks</th></tr></thead><tbody></tbody></table></div>
</div>
<div id="vwSteps"></div>
<p class="vw-status" id="vwStatus"></p>
<div id="vwViewResultWrap" style="display:none;">
<p class="vw-table-name" style="margin-top:1.1rem;">view: top_students</p>
<div class="vw-table-scroll"><table class="vw-mini-table" id="vwViewTable"><thead><tr><th>name</th><th>marks</th></tr></thead><tbody id="vwViewBody"></tbody></table></div>
</div>
<div class="vw-reset-row">
<button class="vw-run-btn is-secondary" id="vwReset" type="button">↺ Reset</button>
</div>
</div>
</div>
<script>
(function () {
const wrapper = document.getElementById('viewrunner');
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 () {
function kw(s) { return '<span class="vw-kw">' + s + '</span>'; }
function str(s) { return '<span class="vw-str">' + s + '</span>'; }
function num(s) { return '<span class="vw-num">' + s + '</span>'; }
function cm(s) { return '<span class="vw-cm">' + s + '</span>'; }
let students = [
{ id: 1, name: 'Anya', marks: 92 },
{ id: 2, name: 'Ravi', marks: 85 },
{ id: 3, name: 'Tina', marks: 97 },
{ id: 4, name: 'Raj', marks: 76 },
{ id: 5, name: 'Sara', marks: 91 }
];
let nextId = 6;
const setupCode =
cm('-- 1. Create the base table') + '\n' +
kw('CREATE TABLE') + ' students (\n id ' + kw('INT AUTO_INCREMENT PRIMARY KEY') + ',\n name ' + kw('VARCHAR') + '(50),\n marks ' + kw('INT') + '\n);\n' +
cm('-- 2. Insert sample data') + '\n' +
kw('INSERT INTO') + ' students (name, marks) ' + kw('VALUES') + '\n' +
'(' + str("'Anya'") + ', ' + num('92') + '),\n(' + str("'Ravi'") + ', ' + num('85') + '),\n(' + str("'Tina'") + ', ' + num('97') + '),\n(' + str("'Raj'") + ', ' + num('76') + '),\n(' + str("'Sara'") + ', ' + num('91') + ');';
const createViewCode = cm('-- 3. Create the view') + '\n' + kw('CREATE VIEW') + ' top_students ' + kw('AS') + '\n' + kw('SELECT') + ' name, marks\n' + kw('FROM') + ' students\n' + kw('WHERE') + ' marks > ' + num('90') + ';';
const queryViewCode = kw('SELECT') + ' * ' + kw('FROM') + ' top_students;';
const insertMoreCode = cm('-- A new student who would also qualify') + '\n' + kw('INSERT INTO') + ' students (name, marks) ' + kw('VALUES') + ' (' + str("'Meena'") + ', ' + num('93') + ');';
const requeryCode = cm('-- Re-run the exact same query — no changes to the view itself') + '\n' + kw('SELECT') + ' * ' + kw('FROM') + ' top_students;';
const steps = [
{ key: 'setup', title: '⚙️ Base Setup', desc: 'Create the students table and insert the sample data.', code: setupCode, type: 'setup' },
{ key: 'createView', title: '📄 Create the View', desc: 'A view doesn\u2019t copy any data — it just saves this query under a name.', code: createViewCode, type: 'createView' },
{ key: 'queryView', title: '🔍 Query the View', desc: 'Query it just like a regular table.', code: queryViewCode, type: 'queryView' },
{ key: 'insertMore', title: '➕ Insert a New Row', desc: 'Add a student directly into the underlying students table — not the view.', code: insertMoreCode, type: 'insertMore' },
{ key: 'requery', title: '🔍 Query the View Again', desc: 'Same view, same query, run again — with no changes made to the view itself.', code: requeryCode, type: 'requery' }
];
const stepsContainer = document.getElementById('vwSteps');
const progress = document.getElementById('vwProgress');
const status = document.getElementById('vwStatus');
const fullCodeContent = document.getElementById('vwFullCodeContent');
const viewResultWrap = document.getElementById('vwViewResultWrap');
const viewBody = document.getElementById('vwViewBody');
fullCodeContent.innerHTML = [setupCode, createViewCode, queryViewCode, insertMoreCode, requeryCode].join('\n\n');
steps.forEach((s, i) => {
const stepEl = document.createElement('div');
stepEl.className = 'vw-step' + (i === 0 ? ' is-revealed' : '');
stepEl.id = 'step-' + s.key;
const label = { setup: 'Setup', createView: 'CREATE VIEW', queryView: 'SELECT * FROM top_students', insertMore: 'INSERT', requery: 'SELECT * FROM top_students again' }[s.key];
let extra = '<div class="vw-run-row"><button class="vw-run-btn" id="btn-' + s.key + '" type="button">▶ Run ' + label + '</button></div>';
if (s.key === 'createView') {
extra += '<div class="vw-view-def" id="vwViewDef">📄 View <b>top_students</b> saved as:<br>SELECT name, marks FROM students WHERE marks > 90</div>';
}
stepEl.innerHTML =
'<div class="vw-step-done-pill"><span>✓ ' + s.title + '</span><span class="chevron">\u25be view code</span></div>' +
'<div class="vw-step-code-full">' +
'<p class="vw-step-label">' + s.title + '</p>' +
'<p class="vw-step-desc">' + s.desc + '</p>' +
'<div class="vw-code-scroll"><div class="vw-code">' + s.code + '</div></div>' +
extra +
'</div>';
stepsContainer.appendChild(stepEl);
});
function updateProgress(doneCount) {
progress.textContent = doneCount + ' / ' + steps.length + ' steps run';
}
updateProgress(0);
function showStatus(text) {
status.textContent = text;
status.classList.add('is-visible');
}
function renderStudents() {
document.querySelector('#vwStudentsTable tbody').innerHTML = students.map(s =>
'<tr class="' + (s.marks > 90 ? 'is-qualifies' : '') + '" data-id="' + s.id + '"><td>' + s.id + '</td><td>' + s.name + '</td><td>' + s.marks + '</td></tr>'
).join('');
}
function renderViewResult() {
const rows = students.filter(s => s.marks > 90);
viewBody.innerHTML = rows.map(s => '<tr class="is-new"><td>' + s.name + '</td><td>' + s.marks + '</td></tr>').join('');
viewResultWrap.style.display = 'block';
return rows;
}
let doneCount = 0;
document.getElementById('btn-setup').addEventListener('click', () => {
document.getElementById('btn-setup').disabled = true;
status.classList.remove('is-visible');
setTimeout(() => {
document.getElementById('vwSourceWrap').style.display = 'block';
renderStudents();
showStatus('✔️ Table created, 5 rows inserted.');
finish('setup');
}, 350);
});
document.getElementById('btn-createView').addEventListener('click', () => {
document.getElementById('btn-createView').disabled = true;
status.classList.remove('is-visible');
setTimeout(() => {
document.getElementById('vwViewDef').classList.add('is-visible');
showStatus('✔️ View created — this is just a saved query, no rows were copied anywhere.');
finish('createView');
}, 350);
});
document.getElementById('btn-queryView').addEventListener('click', () => {
document.getElementById('btn-queryView').disabled = true;
status.classList.remove('is-visible');
setTimeout(() => {
const rows = renderViewResult();
showStatus('✔️ ' + rows.length + ' rows returned — the view ran its saved query against students right now.');
viewResultWrap.scrollIntoView({ behavior: 'smooth', block: 'center' });
finish('queryView');
}, 350);
});
document.getElementById('btn-insertMore').addEventListener('click', () => {
document.getElementById('btn-insertMore').disabled = true;
status.classList.remove('is-visible');
setTimeout(() => {
students.push({ id: nextId++, name: 'Meena', marks: 93 });
renderStudents();
showStatus('✔️ Meena (93) added directly to students — the view "top_students" was not touched at all.');
document.getElementById('vwSourceWrap').scrollIntoView({ behavior: 'smooth', block: 'center' });
finish('insertMore');
}, 350);
});
document.getElementById('btn-requery').addEventListener('click', () => {
document.getElementById('btn-requery').disabled = true;
status.classList.remove('is-visible');
setTimeout(() => {
const rows = renderViewResult();
showStatus('✔️ ' + rows.length + ' rows now — Meena appears automatically. The view re-ran its query live; it was never a static snapshot.');
viewResultWrap.scrollIntoView({ behavior: 'smooth', block: 'center' });
finish('requery');
}, 350);
});
function finish(key) {
document.getElementById('step-' + key).classList.add('is-done');
doneCount++;
updateProgress(doneCount);
const idx = steps.findIndex(s => s.key === key);
const next = steps[idx + 1];
if (next) {
document.getElementById('step-' + next.key).classList.add('is-revealed');
}
}
document.getElementById('vwShowFullBtn').addEventListener('click', function () {
const panel = document.getElementById('vwFullCodePanel');
const on = panel.classList.toggle('is-visible');
this.classList.toggle('is-on', on);
this.textContent = on ? '👁️ Hide full SQL script' : '👁️ Show full SQL script';
});
document.querySelectorAll('.vw-step-done-pill').forEach(pill => {
pill.addEventListener('click', () => {
const step = pill.closest('.vw-step');
step.classList.toggle('is-expanded-done');
pill.querySelector('.chevron').textContent = step.classList.contains('is-expanded-done') ? '\u25b4 hide code' : '\u25be view code';
});
});
document.getElementById('vwReset').addEventListener('click', () => {
students = [
{ id: 1, name: 'Anya', marks: 92 },
{ id: 2, name: 'Ravi', marks: 85 },
{ id: 3, name: 'Tina', marks: 97 },
{ id: 4, name: 'Raj', marks: 76 },
{ id: 5, name: 'Sara', marks: 91 }
];
nextId = 6;
doneCount = 0;
updateProgress(0);
status.classList.remove('is-visible');
document.getElementById('vwSourceWrap').style.display = 'none';
viewResultWrap.style.display = 'none';
viewBody.innerHTML = '';
document.getElementById('vwViewDef').classList.remove('is-visible');
steps.forEach((s, i) => {
const el = document.getElementById('step-' + s.key);
el.classList.remove('is-done', 'is-expanded-done');
el.classList.toggle('is-revealed', i === 0);
document.getElementById('btn-' + s.key).disabled = false;
});
});
})();
</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!');
});✔️ View acts like a table shortcut
✏️ Update a View
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Updating Through a View — Try It Yourself</title>
<style>
.infographic-viewupdaterunner {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--line: #ddd6c9;
--good: #16a34a;
--good-soft: #dcfce7;
--on-accent: #ffffff;
--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: 780px;
margin: 0 auto;
box-sizing: border-box;
overflow-x: hidden;
}
.infographic-viewupdaterunner[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;
--on-accent: #101418;
}
.infographic-viewupdaterunner * { box-sizing: border-box; }
.vu-topbar { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.75rem; gap: 0.5rem; flex-wrap: wrap; }
.vu-progress { font-size: 0.78rem; color: var(--ink-soft); }
.vu-showfull-btn {
font: inherit; font-size: 0.78rem; background: none; border: 1px solid var(--line);
border-radius: 999px; padding: 0.35rem 0.8rem; cursor: pointer; color: var(--ink-soft);
}
.vu-showfull-btn:hover { border-color: var(--accent); color: var(--accent); }
.vu-showfull-btn.is-on { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); }
.vu-fullcode-panel { display: none; margin-bottom: 1.25rem; }
.vu-fullcode-panel.is-visible { display: block; }
.vu-fullcode-scroll { overflow-x: auto; }
.vu-fullcode {
background: var(--ink); color: #d4e2ff; border-radius: 8px; padding: 1rem 1.2rem;
font-family: var(--mono-font); font-size: 0.72rem; line-height: 1.7; white-space: pre; opacity: 0.85;
display: inline-block;
min-width: 100%;
}
.infographic-viewupdaterunner[data-theme="dark"] .vu-fullcode { background: #05070a; }
.vu-frame { background: var(--paper-alt); border: 1px solid var(--line); border-radius: 10px; padding: 1.25rem; }
.vu-kw { color: #9cc5ff; } .vu-str { color: #f8d980; } .vu-num { color: #4ade80; } .vu-cm { color: #7c8aa8; }
.vu-source-label { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--ink-soft); margin: 0 0 0.6rem; }
.vu-table-name { font-size: 0.7rem; color: var(--ink-soft); text-transform: uppercase; letter-spacing: 0.04em; margin: 0.4rem 0 0.2rem; }
.vu-table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; min-width: 0; margin-bottom: 0.6rem; }
table.vu-mini-table {
width: 100%; min-width: 220px; border-collapse: collapse; background: var(--paper);
border-radius: 7px; font-size: 0.85rem;
}
table.vu-mini-table th, table.vu-mini-table td {
border: 1px solid var(--line); padding: 0.45rem 0.6rem; text-align: left; white-space: nowrap;
transition: background 0.4s, color 0.4s;
}
table.vu-mini-table th { background: var(--accent); color: var(--on-accent); font-weight: 700; font-size: 0.7rem; }
table.vu-mini-table tr.is-new td { animation: vu-row-in 0.6s ease; }
@keyframes vu-row-in { from { background: var(--good-soft); } to { background: transparent; } }
table.vu-mini-table tr.is-qualifies td { color: var(--good); font-weight: 700; }
table.vu-mini-table td.is-changed { color: var(--accent); font-weight: 700; animation: vu-row-in 1s ease; }
.vu-step { display: none; margin-bottom: 1rem; }
.vu-step.is-revealed { display: block; animation: vu-step-in 0.4s ease; }
@keyframes vu-step-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }
.vu-step.is-done .vu-step-code-full { display: none; }
.vu-step.is-done .vu-step-done-pill { display: flex; }
.vu-step-done-pill {
display: none; align-items: center; gap: 0.5rem; background: var(--good-soft); color: var(--good);
border-radius: 7px; padding: 0.55rem 0.85rem; font-family: var(--mono-font); font-size: 0.78rem; cursor: pointer;
}
.vu-step-done-pill .chevron { margin-left: auto; font-size: 0.7rem; opacity: 0.7; }
.vu-step.is-expanded-done .vu-step-code-full { display: block; }
.vu-step.is-expanded-done .vu-step-done-pill { background: var(--accent-soft); color: var(--accent); }
.vu-step-label { font-family: var(--display-font); font-size: 1.02rem; margin: 0 0 0.5rem; }
.vu-step-desc { font-size: 0.82rem; color: var(--ink-soft); margin: 0 0 0.7rem; line-height: 1.45; }
.vu-code-scroll { overflow-x: auto; }
.vu-code {
background: var(--ink); color: #d4e2ff; border-radius: 8px; padding: 0.8rem 1rem;
font-family: var(--mono-font); font-size: 0.78rem; line-height: 1.6; white-space: pre;
display: inline-block;
min-width: 100%;
}
.infographic-viewupdaterunner[data-theme="dark"] .vu-code { background: #05070a; }
.vu-run-row { display: flex; justify-content: center; margin-top: 0.85rem; }
.vu-run-btn {
font: inherit; font-size: 0.85rem; background: var(--accent); color: var(--on-accent);
border: none; border-radius: 7px; padding: 0.55rem 1.1rem; cursor: pointer;
}
.vu-run-btn:hover { opacity: 0.9; }
.vu-run-btn:disabled { opacity: 0.55; cursor: wait; }
.vu-run-btn.is-secondary { background: var(--paper); color: var(--ink); border: 1px solid var(--line); }
.vu-view-def {
margin-top: 0.85rem; padding: 0.7rem 0.9rem; border-radius: 8px; border: 2px dashed var(--accent);
background: var(--accent-soft); color: var(--accent); font-family: var(--mono-font); font-size: 0.78rem;
line-height: 1.5; display: none;
}
.vu-view-def.is-visible { display: block; }
.vu-status {
text-align: center; font-size: 0.82rem; margin-top: 0.85rem; padding: 0.5rem 0.8rem;
border-radius: 7px; display: none; background: var(--good-soft); color: var(--good);
}
.vu-status.is-visible { display: block; animation: vu-step-in 0.3s ease; }
.vu-reset-row { display: flex; justify-content: center; margin-top: 1.25rem; }
@media (prefers-reduced-motion: reduce) {
.infographic-viewupdaterunner *, .infographic-viewupdaterunner *::before, .infographic-viewupdaterunner *::after {
transition-duration: 0.001ms !important; animation-duration: 0.001ms !important;
}
}
</style>
</head>
<body>
<div class="infographic-viewupdaterunner" id="viewupdaterunner">
<div class="vu-topbar">
<span class="vu-progress" id="vuProgress"></span>
<button class="vu-showfull-btn" id="vuShowFullBtn" type="button">👁️ Show full SQL script</button>
</div>
<div class="vu-fullcode-panel" id="vuFullCodePanel">
<div class="vu-fullcode-scroll">
<div class="vu-fullcode" id="vuFullCodeContent"></div>
</div>
</div>
<div class="vu-frame">
<div id="vuSourceWrap" style="display:none;">
<p class="vu-source-label">Table: students</p>
<div class="vu-table-scroll"><table class="vu-mini-table" id="vuStudentsTable"><thead><tr><th>id</th><th>name</th><th>marks</th></tr></thead><tbody></tbody></table></div>
</div>
<div id="vuSteps"></div>
<p class="vu-status" id="vuStatus"></p>
<div id="vuViewResultWrap" style="display:none;">
<p class="vu-table-name" style="margin-top:1.1rem;">view: top_students</p>
<div class="vu-table-scroll"><table class="vu-mini-table" id="vuViewTable"><thead><tr><th>name</th><th>marks</th></tr></thead><tbody id="vuViewBody"></tbody></table></div>
</div>
<div class="vu-reset-row">
<button class="vu-run-btn is-secondary" id="vuReset" type="button">↺ Reset</button>
</div>
</div>
</div>
<script>
(function () {
const wrapper = document.getElementById('viewupdaterunner');
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 () {
function kw(s) { return '<span class="vu-kw">' + s + '</span>'; }
function str(s) { return '<span class="vu-str">' + s + '</span>'; }
function num(s) { return '<span class="vu-num">' + s + '</span>'; }
function cm(s) { return '<span class="vu-cm">' + s + '</span>'; }
let students = [
{ id: 1, name: 'Anya', marks: 92 },
{ id: 2, name: 'Ravi', marks: 85 },
{ id: 3, name: 'Tina', marks: 97 },
{ id: 4, name: 'Raj', marks: 76 },
{ id: 5, name: 'Sara', marks: 91 }
];
const setupCode =
cm('-- 1. Create the base table (if not exists)') + '\n' +
kw('CREATE TABLE IF NOT EXISTS') + ' students (\n id ' + kw('INT AUTO_INCREMENT PRIMARY KEY') + ',\n name ' + kw('VARCHAR') + '(50),\n marks ' + kw('INT') + '\n);\n' +
cm('-- 2. Insert sample data') + '\n' +
kw('INSERT INTO') + ' students (name, marks) ' + kw('VALUES') + '\n' +
'(' + str("'Anya'") + ', ' + num('92') + '),\n(' + str("'Ravi'") + ', ' + num('85') + '),\n(' + str("'Tina'") + ', ' + num('97') + '),\n(' + str("'Raj'") + ', ' + num('76') + '),\n(' + str("'Sara'") + ', ' + num('91') + ');';
const createViewCode = cm('-- 3. Create or replace the view') + '\n' + kw('CREATE OR REPLACE VIEW') + ' top_students ' + kw('AS') + '\n' + kw('SELECT') + ' name, marks\n' + kw('FROM') + ' students\n' + kw('WHERE') + ' marks > ' + num('95') + ';';
const queryViewCode = kw('SELECT') + ' * ' + kw('FROM') + ' top_students;';
const updateViewCode = cm('-- 4. Updating the view') + '\n' + kw('UPDATE') + ' top_students\n' + kw('SET') + ' marks = ' + num('99') + '\n' + kw('WHERE') + ' name = ' + str("'Tina'") + ';';
const requeryCode = cm('-- Query the view again') + '\n' + kw('SELECT') + ' * ' + kw('FROM') + ' top_students;';
const steps = [
{ key: 'setup', title: '⚙️ Base Setup', desc: 'Create the students table (if needed) and insert the sample data.', code: setupCode, type: 'setup' },
{ key: 'createView', title: '📄 CREATE OR REPLACE VIEW', desc: 'This threshold is stricter than before — marks > 95 — and OR REPLACE means it redefines the view if one already existed, no DROP needed first.', code: createViewCode, type: 'createView' },
{ key: 'queryView', title: '🔍 Query the View', desc: 'With this stricter threshold, only one student qualifies.', code: queryViewCode, type: 'queryView' },
{ key: 'updateView', title: '✏️ Update Through the View', desc: 'Since this view is simple — one table, no aggregation — it\u2019s updatable. The UPDATE targets top_students, but watch what actually changes.', code: updateViewCode, type: 'updateView' },
{ key: 'requery', title: '🔍 Query the View Again', desc: 'See the result of the update reflected back.', code: requeryCode, type: 'requery' }
];
const stepsContainer = document.getElementById('vuSteps');
const progress = document.getElementById('vuProgress');
const status = document.getElementById('vuStatus');
const fullCodeContent = document.getElementById('vuFullCodeContent');
const viewResultWrap = document.getElementById('vuViewResultWrap');
const viewBody = document.getElementById('vuViewBody');
fullCodeContent.innerHTML = [setupCode, createViewCode, queryViewCode, updateViewCode, requeryCode].join('\n\n');
steps.forEach((s, i) => {
const stepEl = document.createElement('div');
stepEl.className = 'vu-step' + (i === 0 ? ' is-revealed' : '');
stepEl.id = 'step-' + s.key;
const label = { setup: 'Setup', createView: 'CREATE OR REPLACE VIEW', queryView: 'SELECT * FROM top_students', updateView: 'UPDATE top_students', requery: 'SELECT * FROM top_students again' }[s.key];
let extra = '<div class="vu-run-row"><button class="vu-run-btn" id="btn-' + s.key + '" type="button">▶ Run ' + label + '</button></div>';
if (s.key === 'createView') {
extra += '<div class="vu-view-def" id="vuViewDef">📄 View <b>top_students</b> saved (replacing any previous version) as:<br>SELECT name, marks FROM students WHERE marks > 95</div>';
}
stepEl.innerHTML =
'<div class="vu-step-done-pill"><span>✓ ' + s.title + '</span><span class="chevron">\u25be view code</span></div>' +
'<div class="vu-step-code-full">' +
'<p class="vu-step-label">' + s.title + '</p>' +
'<p class="vu-step-desc">' + s.desc + '</p>' +
'<div class="vu-code-scroll"><div class="vu-code">' + s.code + '</div></div>' +
extra +
'</div>';
stepsContainer.appendChild(stepEl);
});
function updateProgress(doneCount) {
progress.textContent = doneCount + ' / ' + steps.length + ' steps run';
}
updateProgress(0);
function showStatus(text) {
status.textContent = text;
status.classList.add('is-visible');
}
function renderStudents(highlightId) {
document.querySelector('#vuStudentsTable tbody').innerHTML = students.map(s =>
'<tr class="' + (s.marks > 95 ? 'is-qualifies' : '') + '" data-id="' + s.id + '"><td>' + s.id + '</td><td>' + s.name + '</td><td' + (highlightId === s.id ? ' class="is-changed"' : '') + '>' + s.marks + '</td></tr>'
).join('');
}
function renderViewResult() {
const rows = students.filter(s => s.marks > 95);
viewBody.innerHTML = rows.map(s => '<tr class="is-new"><td>' + s.name + '</td><td>' + s.marks + '</td></tr>').join('');
viewResultWrap.style.display = 'block';
return rows;
}
let doneCount = 0;
document.getElementById('btn-setup').addEventListener('click', () => {
document.getElementById('btn-setup').disabled = true;
status.classList.remove('is-visible');
setTimeout(() => {
document.getElementById('vuSourceWrap').style.display = 'block';
renderStudents();
showStatus('✔️ Table created, 5 rows inserted.');
finish('setup');
}, 350);
});
document.getElementById('btn-createView').addEventListener('click', () => {
document.getElementById('btn-createView').disabled = true;
status.classList.remove('is-visible');
setTimeout(() => {
document.getElementById('vuViewDef').classList.add('is-visible');
showStatus('✔️ View saved with the new definition (marks > 95).');
finish('createView');
}, 350);
});
document.getElementById('btn-queryView').addEventListener('click', () => {
document.getElementById('btn-queryView').disabled = true;
status.classList.remove('is-visible');
setTimeout(() => {
const rows = renderViewResult();
showStatus('✔️ ' + rows.length + ' row returned — only Tina (97) clears the new marks > 95 bar.');
viewResultWrap.scrollIntoView({ behavior: 'smooth', block: 'center' });
finish('queryView');
}, 350);
});
document.getElementById('btn-updateView').addEventListener('click', () => {
document.getElementById('btn-updateView').disabled = true;
status.classList.remove('is-visible');
setTimeout(() => {
const tina = students.find(s => s.name === 'Tina');
tina.marks = 99;
renderStudents(tina.id);
showStatus('✔️ Tina\u2019s marks are now 99 — in the students table itself. The UPDATE passed straight through the view to the real data underneath.');
document.getElementById('vuSourceWrap').scrollIntoView({ behavior: 'smooth', block: 'center' });
finish('updateView');
}, 350);
});
document.getElementById('btn-requery').addEventListener('click', () => {
document.getElementById('btn-requery').disabled = true;
status.classList.remove('is-visible');
setTimeout(() => {
const rows = renderViewResult();
showStatus('✔️ Tina now shows 99 through the view too — same student, same underlying row, just read two different ways.');
viewResultWrap.scrollIntoView({ behavior: 'smooth', block: 'center' });
finish('requery');
}, 350);
});
function finish(key) {
document.getElementById('step-' + key).classList.add('is-done');
doneCount++;
updateProgress(doneCount);
const idx = steps.findIndex(s => s.key === key);
const next = steps[idx + 1];
if (next) {
document.getElementById('step-' + next.key).classList.add('is-revealed');
}
}
document.getElementById('vuShowFullBtn').addEventListener('click', function () {
const panel = document.getElementById('vuFullCodePanel');
const on = panel.classList.toggle('is-visible');
this.classList.toggle('is-on', on);
this.textContent = on ? '👁️ Hide full SQL script' : '👁️ Show full SQL script';
});
document.querySelectorAll('.vu-step-done-pill').forEach(pill => {
pill.addEventListener('click', () => {
const step = pill.closest('.vu-step');
step.classList.toggle('is-expanded-done');
pill.querySelector('.chevron').textContent = step.classList.contains('is-expanded-done') ? '\u25b4 hide code' : '\u25be view code';
});
});
document.getElementById('vuReset').addEventListener('click', () => {
students = [
{ id: 1, name: 'Anya', marks: 92 },
{ id: 2, name: 'Ravi', marks: 85 },
{ id: 3, name: 'Tina', marks: 97 },
{ id: 4, name: 'Raj', marks: 76 },
{ id: 5, name: 'Sara', marks: 91 }
];
doneCount = 0;
updateProgress(0);
status.classList.remove('is-visible');
document.getElementById('vuSourceWrap').style.display = 'none';
viewResultWrap.style.display = 'none';
viewBody.innerHTML = '';
document.getElementById('vuViewDef').classList.remove('is-visible');
steps.forEach((s, i) => {
const el = document.getElementById('step-' + s.key);
el.classList.remove('is-done', 'is-expanded-done');
el.classList.toggle('is-revealed', i === 0);
document.getElementById('btn-' + s.key).disabled = false;
});
});
})();
</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!');
});✅ Summary Table
Operation | Command Example |
|---|---|
👁️ Create View |
|
🧼 Use View |
|
✏️ Update View |
|