Set operations combine the results of two or more SELECT queries into a single result set β just like in mathematics.
π Rules:
Number of columns and their data types must match
Column order matters
By default, they remove duplicates
π€― Base Setup for further examples:
-- 1. Create the first table
CREATE TABLE science_students (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50)
);
-- 2. Create the second table
CREATE TABLE math_students (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50)
);
-- 3. Insert sample data
INSERT INTO science_students (name) VALUES
('Anya'),
('Ravi'),
('Sara');
INSERT INTO math_students (name) VALUES
('Ravi'),
('Tina'),
('Meena');π UNION β Combine & Remove Duplicates
Returns all unique rows from both queries.
π Example:
-- UNION query to get unique student names from both tables
SELECT name FROM science_students
UNION
SELECT name FROM math_students;βοΈ Combines names from both tables
βοΈ Removes any duplicate names
β UNION ALL β Combine All (Including Duplicates)
Same as UNION but keeps duplicate rows
π Example:
-- Use UNION ALL to combine names (including duplicates)
SELECT name FROM science_students
UNION ALL
SELECT name FROM math_students;βοΈ Faster than UNION
βοΈ Includes repeated names
π― INTERSECT β Common Rows Only
Returns only the rows that exist in both queries.
π Example:
-- β
INTERSECT equivalent using INNER JOIN
SELECT s.name
FROM science_students s
INNER JOIN math_students m ON s.name = m.name;-- β
INTERSECT equivalent using IN
SELECT name
FROM science_students
WHERE name IN (SELECT name FROM math_students);βοΈ Shows students enrolled in both subjects
β Not supported in MySQL (can be emulated using INNER JOIN or IN)
β MINUS (or EXCEPT) β Rows in First, Not in Second
Returns rows from the first query that do not appear in the second.
π Example:
-- β
MINUS Equivalent using LEFT JOIN
SELECT s.name
FROM science_students s
LEFT JOIN math_students m ON s.name = m.name
WHERE m.name IS NULL;-- β
MINUS Equivalent using NOT IN
SELECT name
FROM science_students
WHERE name NOT IN (SELECT name FROM math_students);βοΈ Shows students only in science, not in math
β
MINUS β Oracle
β
EXCEPT β PostgreSQL & SQL Server
β Not supported in MySQL directly
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>UNION, INTERSECT, MINUS β Try It Yourself</title>
<style>
.infographic-setopsrunner {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--line: #ddd6c9;
--good: #16a34a;
--good-soft: #dcfce7;
--warn: #b45309;
--warn-soft: #fef3c7;
--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: 800px;
margin: 0 auto;
box-sizing: border-box;
overflow-x: hidden;
}
.infographic-setopsrunner[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;
--warn: #fbbf24;
--warn-soft: #3a2f0e;
--on-accent: #101418;
}
.infographic-setopsrunner * { box-sizing: border-box; }
.so-topbar { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.75rem; gap: 0.5rem; flex-wrap: wrap; }
.so-progress { font-size: 0.78rem; color: var(--ink-soft); }
.so-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);
}
.so-showfull-btn:hover { border-color: var(--accent); color: var(--accent); }
.so-showfull-btn.is-on { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); }
.so-fullcode-panel { display: none; margin-bottom: 1.25rem; }
.so-fullcode-panel.is-visible { display: block; }
.so-fullcode-scroll { overflow-x: auto; }
.so-fullcode {
background: var(--ink); color: #d4e2ff; border-radius: 8px; padding: 1rem 1.2rem;
font-family: var(--mono-font); font-size: 0.7rem; line-height: 1.7; white-space: pre; opacity: 0.85;
display: inline-block;
min-width: 100%;
}
.infographic-setopsrunner[data-theme="dark"] .so-fullcode { background: #05070a; }
.so-frame { background: var(--paper-alt); border: 1px solid var(--line); border-radius: 10px; padding: 1.25rem; }
.so-kw { color: #9cc5ff; } .so-str { color: #f8d980; } .so-cm { color: #7c8aa8; }
.so-source-label { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--ink-soft); margin: 0 0 0.6rem; }
.so-table-name { font-size: 0.7rem; color: var(--ink-soft); text-transform: uppercase; letter-spacing: 0.04em; margin: 0.4rem 0 0.2rem; }
.so-src-row { display: flex; gap: 1rem; flex-wrap: wrap; }
.so-src-col { flex: 1 1 160px; min-width: 0; }
.so-mini-table-scroll { overflow-x: auto; margin-bottom: 0.6rem; }
table.so-mini-table {
width: 100%; min-width: 140px; border-collapse: collapse; background: var(--paper);
border-radius: 7px; font-size: 0.8rem;
}
table.so-mini-table th, table.so-mini-table td {
border: 1px solid var(--line); padding: 0.4rem 0.55rem; text-align: left; white-space: nowrap;
}
table.so-mini-table th { background: var(--accent); color: var(--on-accent); font-weight: 700; font-size: 0.68rem; }
table.so-mini-table tr.is-new td { animation: so-row-in 0.6s ease; }
@keyframes so-row-in { from { background: var(--good-soft); } to { background: transparent; } }
.so-step { display: none; margin-bottom: 1rem; }
.so-step.is-revealed { display: block; animation: so-step-in 0.4s ease; }
@keyframes so-step-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }
.so-step.is-done .so-step-code-full { display: none; }
.so-step.is-done .so-step-done-pill { display: flex; }
.so-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;
}
.so-step-done-pill .chevron { margin-left: auto; font-size: 0.7rem; opacity: 0.7; }
.so-step.is-expanded-done .so-step-code-full { display: block; }
.so-step.is-expanded-done .so-step-done-pill { background: var(--accent-soft); color: var(--accent); }
.so-step-label { font-family: var(--display-font); font-size: 1.02rem; margin: 0 0 0.5rem; }
.so-step-desc { font-size: 0.82rem; color: var(--ink-soft); margin: 0 0 0.7rem; line-height: 1.45; }
.so-step-support {
font-size: 0.78rem; color: var(--warn); background: var(--warn-soft); border-radius: 7px;
padding: 0.5rem 0.7rem; margin-top: 0.7rem; line-height: 1.4;
}
.so-code-scroll { overflow-x: auto; margin-bottom: 0.6rem; }
.so-code {
background: var(--ink); color: #d4e2ff; border-radius: 8px; padding: 0.75rem 0.95rem;
font-family: var(--mono-font); font-size: 0.76rem; line-height: 1.55; white-space: pre;
display: inline-block;
min-width: 100%;
}
.infographic-setopsrunner[data-theme="dark"] .so-code { background: #05070a; }
.so-code-alt-label { font-size: 0.72rem; color: var(--ink-soft); margin: 0.5rem 0 0.3rem; }
.so-run-row { display: flex; justify-content: center; margin-top: 0.85rem; }
.so-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;
}
.so-run-btn:hover { opacity: 0.9; }
.so-run-btn:disabled { opacity: 0.55; cursor: wait; }
.so-run-btn.is-secondary { background: var(--paper); color: var(--ink); border: 1px solid var(--line); }
.so-output-label { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--ink-soft); margin: 1.1rem 0 0.6rem; }
.so-table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; min-width: 0; }
table.so-table {
width: 100%; min-width: 160px; border-collapse: collapse; background: var(--paper);
border-radius: 8px; font-size: 0.88rem;
}
table.so-table th, table.so-table td {
border: 1px solid var(--line); padding: 0.5rem 0.7rem; text-align: left; white-space: nowrap;
}
table.so-table th { background: var(--accent); color: var(--on-accent); font-weight: 700; font-size: 0.75rem; }
table.so-table tr.is-new td { animation: so-row-in 0.6s ease; }
table.so-table tr.is-dup td { color: var(--warn); font-weight: 600; }
.so-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);
}
.so-status.is-visible { display: block; animation: so-step-in 0.3s ease; }
.so-reset-row { display: flex; justify-content: center; margin-top: 1.25rem; }
@media (prefers-reduced-motion: reduce) {
.infographic-setopsrunner *, .infographic-setopsrunner *::before, .infographic-setopsrunner *::after {
transition-duration: 0.001ms !important; animation-duration: 0.001ms !important;
}
}
</style>
</head>
<body>
<div class="infographic-setopsrunner" id="setopsrunner">
<div class="so-topbar">
<span class="so-progress" id="soProgress"></span>
<button class="so-showfull-btn" id="soShowFullBtn" type="button">ποΈ Show full SQL script</button>
</div>
<div class="so-fullcode-panel" id="soFullCodePanel">
<div class="so-fullcode-scroll">
<div class="so-fullcode" id="soFullCodeContent"></div>
</div>
</div>
<div class="so-frame">
<div id="soSourceWrap" style="display:none;">
<p class="so-source-label">Source Tables</p>
<div class="so-src-row">
<div class="so-src-col">
<p class="so-table-name">science_students</p>
<div class="so-mini-table-scroll"><table class="so-mini-table" id="soSciTable"><thead><tr><th>id</th><th>name</th></tr></thead><tbody></tbody></table></div>
</div>
<div class="so-src-col">
<p class="so-table-name">math_students</p>
<div class="so-mini-table-scroll"><table class="so-mini-table" id="soMathTable"><thead><tr><th>id</th><th>name</th></tr></thead><tbody></tbody></table></div>
</div>
</div>
</div>
<div id="soSteps"></div>
<p class="so-status" id="soStatus"></p>
<p class="so-output-label" id="soOutputLabel" style="display:none;">Query Result</p>
<div class="so-table-scroll" id="soTableScroll" style="display:none;">
<table class="so-table" id="soTable"></table>
</div>
<div class="so-reset-row">
<button class="so-run-btn is-secondary" id="soReset" type="button">βΊ Reset</button>
</div>
</div>
</div>
<script>
(function () {
const wrapper = document.getElementById('setopsrunner');
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="so-kw">' + s + '</span>'; }
function str(s) { return '<span class="so-str">' + s + '</span>'; }
function cm(s) { return '<span class="so-cm">' + s + '</span>'; }
const scienceStudents = [{ id: 1, name: 'Anya' }, { id: 2, name: 'Ravi' }, { id: 3, name: 'Sara' }];
const mathStudents = [{ id: 1, name: 'Ravi' }, { id: 2, name: 'Tina' }, { id: 3, name: 'Meena' }];
const setupCode =
cm('-- 1. Create the first table') + '\n' +
kw('CREATE TABLE') + ' science_students (\n id ' + kw('INT AUTO_INCREMENT PRIMARY KEY') + ',\n name ' + kw('VARCHAR') + '(50)\n);\n\n' +
cm('-- 2. Create the second table') + '\n' +
kw('CREATE TABLE') + ' math_students (\n id ' + kw('INT AUTO_INCREMENT PRIMARY KEY') + ',\n name ' + kw('VARCHAR') + '(50)\n);\n\n' +
cm('-- 3. Insert sample data') + '\n' +
kw('INSERT INTO') + ' science_students (name) ' + kw('VALUES') + '\n(' + str("'Anya'") + '),\n(' + str("'Ravi'") + '),\n(' + str("'Sara'") + ');\n\n' +
kw('INSERT INTO') + ' math_students (name) ' + kw('VALUES') + '\n(' + str("'Ravi'") + '),\n(' + str("'Tina'") + '),\n(' + str("'Meena'") + ');';
const unionCode = cm('-- UNION query to get unique student names from both tables') + '\n' + kw('SELECT') + ' name ' + kw('FROM') + ' science_students\n' + kw('UNION') + '\n' + kw('SELECT') + ' name ' + kw('FROM') + ' math_students;';
const unionAllCode = cm('-- Use UNION ALL to combine names (including duplicates)') + '\n' + kw('SELECT') + ' name ' + kw('FROM') + ' science_students\n' + kw('UNION ALL') + '\n' + kw('SELECT') + ' name ' + kw('FROM') + ' math_students;';
const intersectCode = cm('-- INTERSECT equivalent using INNER JOIN') + '\n' + kw('SELECT') + ' s.name\n' + kw('FROM') + ' science_students s\n' + kw('INNER JOIN') + ' math_students m ' + kw('ON') + ' s.name = m.name;';
const intersectAltCode = cm('-- INTERSECT equivalent using IN') + '\n' + kw('SELECT') + ' name\n' + kw('FROM') + ' science_students\n' + kw('WHERE') + ' name ' + kw('IN') + ' (' + kw('SELECT') + ' name ' + kw('FROM') + ' math_students);';
const minusCode = cm('-- MINUS equivalent using LEFT JOIN') + '\n' + kw('SELECT') + ' s.name\n' + kw('FROM') + ' science_students s\n' + kw('LEFT JOIN') + ' math_students m ' + kw('ON') + ' s.name = m.name\n' + kw('WHERE') + ' m.name ' + kw('IS NULL') + ';';
const minusAltCode = cm('-- MINUS equivalent using NOT IN') + '\n' + kw('SELECT') + ' name\n' + kw('FROM') + ' science_students\n' + kw('WHERE') + ' name ' + kw('NOT IN') + ' (' + kw('SELECT') + ' name ' + kw('FROM') + ' math_students);';
function unionRows() {
const seen = new Set();
const rows = [];
[...scienceStudents, ...mathStudents].forEach(s => {
if (!seen.has(s.name)) { seen.add(s.name); rows.push([s.name]); }
});
return rows;
}
function unionAllRows() {
return [...scienceStudents, ...mathStudents].map(s => [s.name]);
}
function intersectRows() {
return scienceStudents.filter(s => mathStudents.some(m => m.name === s.name)).map(s => [s.name]);
}
function minusRows() {
return scienceStudents.filter(s => !mathStudents.some(m => m.name === s.name)).map(s => [s.name]);
}
const steps = [
{ key: 'setup', title: 'π€― Base Setup', desc: 'Two independent tables β no foreign key between them this time.', code: setupCode, type: 'setup' },
{ key: 'union', title: 'π UNION', desc: 'Combines both lists into one, removing duplicates.', code: unionCode, getRows: unionRows, dupNote: false },
{ key: 'unionAll', title: 'β UNION ALL', desc: 'Same combination, but duplicates are kept β faster since no de-duplication happens.', code: unionAllCode, getRows: unionAllRows, dupNote: true },
{ key: 'intersect', title: 'π― INTERSECT (emulated)', desc: 'Only names that appear in both tables.', code: intersectCode, altCode: intersectAltCode, altLabel: 'Equivalent using IN', getRows: intersectRows,
support: 'β INTERSECT itself isn\u2019t supported in MySQL β this is why it\u2019s emulated with INNER JOIN or IN instead.' },
{ key: 'minus', title: 'β MINUS / EXCEPT (emulated)', desc: 'Rows in science_students that do NOT appear in math_students.', code: minusCode, altCode: minusAltCode, altLabel: 'Equivalent using NOT IN', getRows: minusRows,
support: 'β
MINUS β Oracle. β
EXCEPT β PostgreSQL & SQL Server. β Neither is supported directly in MySQL β hence the LEFT JOIN / NOT IN versions here.' }
];
const stepsContainer = document.getElementById('soSteps');
const progress = document.getElementById('soProgress');
const outputLabel = document.getElementById('soOutputLabel');
const tableScroll = document.getElementById('soTableScroll');
const table = document.getElementById('soTable');
const status = document.getElementById('soStatus');
const fullCodeContent = document.getElementById('soFullCodeContent');
fullCodeContent.innerHTML = [setupCode, unionCode, unionAllCode, intersectCode, intersectAltCode, minusCode, minusAltCode].join('\n\n');
steps.forEach((s, i) => {
const stepEl = document.createElement('div');
stepEl.className = 'so-step' + (i === 0 ? ' is-revealed' : '');
stepEl.id = 'step-' + s.key;
const label = s.type === 'setup' ? 'Setup' : ('Run ' + s.title.replace(/^[^\s]+\s?/, '').replace(/\s?\(emulated\)/, ''));
stepEl.innerHTML =
'<div class="so-step-done-pill"><span>β ' + s.title + '</span><span class="chevron">\u25be view code</span></div>' +
'<div class="so-step-code-full">' +
'<p class="so-step-label">' + s.title + '</p>' +
'<p class="so-step-desc">' + s.desc + '</p>' +
'<div class="so-code-scroll"><div class="so-code">' + s.code + '</div></div>' +
(s.altCode ? '<p class="so-code-alt-label">' + s.altLabel + '</p><div class="so-code-scroll"><div class="so-code">' + s.altCode + '</div></div>' : '') +
'<div class="so-run-row"><button class="so-run-btn" id="btn-' + s.key + '" type="button">βΆ ' + label + '</button></div>' +
(s.support ? '<p class="so-step-support">' + s.support + '</p>' : '') +
'</div>';
stepsContainer.appendChild(stepEl);
});
function updateProgress(doneCount) {
progress.textContent = doneCount + ' / ' + steps.length + ' queries run';
}
updateProgress(0);
function showStatus(text) {
status.textContent = text;
status.classList.add('is-visible');
}
function renderResult(rows, flagDup) {
const counts = {};
rows.forEach(r => { counts[r[0]] = (counts[r[0]] || 0) + 1; });
let html = '<thead><tr><th>name</th></tr></thead><tbody>';
rows.forEach(r => {
const isDup = flagDup && counts[r[0]] > 1;
html += '<tr class="is-new' + (isDup ? ' is-dup' : '') + '"><td>' + r[0] + '</td></tr>';
});
html += '</tbody>';
table.innerHTML = html;
outputLabel.style.display = 'block';
tableScroll.style.display = 'block';
}
let doneCount = 0;
document.getElementById('btn-setup').addEventListener('click', () => {
document.getElementById('btn-setup').disabled = true;
status.classList.remove('is-visible');
setTimeout(() => {
document.getElementById('soSourceWrap').style.display = 'block';
document.querySelector('#soSciTable tbody').innerHTML = scienceStudents.map(s => '<tr class="is-new"><td>' + s.id + '</td><td>' + s.name + '</td></tr>').join('');
document.querySelector('#soMathTable tbody').innerHTML = mathStudents.map(s => '<tr class="is-new"><td>' + s.id + '</td><td>' + s.name + '</td></tr>').join('');
showStatus('βοΈ Both tables created, all sample data inserted.');
document.getElementById('soSourceWrap').scrollIntoView({ behavior: 'smooth', block: 'center' });
finish('setup');
}, 350);
});
steps.slice(1).forEach(s => {
document.getElementById('btn-' + s.key).addEventListener('click', () => {
document.getElementById('btn-' + s.key).disabled = true;
status.classList.remove('is-visible');
setTimeout(() => {
const rows = s.getRows();
renderResult(rows, s.dupNote);
showStatus('βοΈ ' + rows.length + ' row' + (rows.length === 1 ? '' : 's') + ' returned.' + (s.dupNote ? ' Repeated names are highlighted.' : ''));
tableScroll.scrollIntoView({ behavior: 'smooth', block: 'center' });
finish(s.key);
}, 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) {
const nextEl = document.getElementById('step-' + next.key);
nextEl.classList.add('is-revealed');
}
}
document.getElementById('soShowFullBtn').addEventListener('click', function () {
const panel = document.getElementById('soFullCodePanel');
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('.so-step-done-pill').forEach(pill => {
pill.addEventListener('click', () => {
const step = pill.closest('.so-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('soReset').addEventListener('click', () => {
doneCount = 0;
updateProgress(0);
status.classList.remove('is-visible');
outputLabel.style.display = 'none';
tableScroll.style.display = 'none';
table.innerHTML = '';
document.getElementById('soSourceWrap').style.display = 'none';
document.querySelector('#soSciTable tbody').innerHTML = '';
document.querySelector('#soMathTable tbody').innerHTML = '';
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
Set Operation | Description | Removes Duplicates | MySQL Support |
|---|---|---|---|
π | Combines results, removes duplicates | β Yes | β Yes |
β | Combines results, keeps duplicates | β No | β Yes |
π― | Common rows in both queries | β Yes | β No (use JOIN) |
β | Rows in 1st query but not in 2nd | β Yes | β No (use |