19. UNION & UNION ALL -- Combining Result Sets
Level: Beginner
- UNION syntax -- combine two SELECT queries
- UNION vs UNION ALL (duplicates)
- Matching column count and types
- UNION with ORDER BY
- UNION vs JOIN difference
- Stack results vertically
- Common UNION mistakes
- UNION performance
JOINs connect tables horizontally (add columns). UNION stacks results vertically (add rows). This article teaches combining query results.
Why UNION Matters for Backend Developers
APIs need combined data from different sources:
Frontend asks: "Get all people in school (students + teachers + staff)"
v
Backend needs: Combine Student + Teacher + Staff tables
v
UNION: Stack rows from 3 tables into 1 result
v
Single result set with all people
UNION solves "combine multiple queries" problems.
UNION Syntax
SELECT Column1, Column2 FROM Table1
UNION
SELECT Column1, Column2 FROM Table2;
Rules:
- Same number of columns in both queries
- Matching column types
- UNION removes duplicates
- ORDER BY applies to final result
Example 1: UNION All Students and Teachers
Combine students and teachers:
SELECT
s.Name AS PersonName,
'Student' AS PersonType
FROM Student s
UNION
SELECT
t.Name AS PersonName,
'Teacher' AS PersonType
FROM Teacher t;
Result (students and teachers):
PersonName | PersonType
Ravi Kumar | Student
Priya Sharma | Student
Dr. Mehta | Teacher
Mrs. Rao | Teacher
Stacks: All students (2 rows) + All teachers (2 rows) = 4 rows. No duplicates.
Example 2: UNION vs UNION ALL (duplicates)
Get students or teachers named "Kumar":
SELECT Name FROM Student WHERE Name LIKE '%Kumar%'
UNION
SELECT Name FROM Student WHERE Name LIKE '%Sharma%';
Result (UNION removes duplicates):
Name
Ravi Kumar
Priya Sharma
Same table queried twice. UNION shows each name once.
With UNION ALL:
SELECT Name FROM Student WHERE Name LIKE '%Kumar%'
UNION ALL
SELECT Name FROM Student WHERE Name LIKE '%Sharma%';
Result (all rows):
Name
Ravi Kumar
Priya Sharma
Same count (no duplicates in this case). But if "Ravi Kumar" matched both conditions, UNION ALL shows both rows.
Example 3: Combine Students from Multiple Classes
Get top 3 scorers from class 10-A and 10-B:
SELECT
s.Name AS Student,
s.ClassName,
r.MarksObtained
FROM Student s
INNER JOIN ExamResult r ON s.StudentId = r.StudentId
WHERE s.ClassName = '10-A'
ORDER BY r.MarksObtained DESC
UNION
SELECT
s.Name AS Student,
s.ClassName,
r.MarksObtained
FROM Student s
INNER JOIN ExamResult r ON s.StudentId = r.StudentId
WHERE s.ClassName = '10-B'
ORDER BY r.MarksObtained DESC;
Result (top scorers from both classes):
Student | ClassName | MarksObtained
Arjun Reddy | 10-B | 92
Priya Sharma| 10-A | 90
Ravi Kumar | 10-A | 88
Combines two separate filtered queries. Removes duplicate student records.
Example 4: All People Report (Students, Teachers, Staff)
Get all people with roles:
SELECT
s.Name,
'Student' AS Role,
s.ClassName AS Details
FROM Student s
UNION
SELECT
t.Name,
'Teacher' AS Role,
t.Qualification AS Details
FROM Teacher t
UNION
SELECT
st.Name,
'Staff' AS Role,
st.Designation AS Details
FROM Staff st
ORDER BY Name;
Result (all school people):
Name | Role | Details
Arjun Reddy | Student | 10-B
Dr. Mehta | Teacher | M.Sc. Physics
Kiran Rao | Staff | Librarian
Mrs. Rao | Teacher | B.A. English
Priya Sharma| Student | 10-A
Stacks 3 different tables. Shows all with consistent columns.
Example 5: UNION to Find Unmatched (alternative to FULL OUTER)
Get unassigned teachers AND subjects:
SELECT
t.Name AS Teacher,
NULL AS Subject
FROM Teacher t
WHERE NOT EXISTS (
SELECT 1 FROM Subject WHERE TeacherId = t.TeacherId
)
UNION
SELECT
NULL AS Teacher,
s.Name AS Subject
FROM Subject s
WHERE NOT EXISTS (
SELECT 1 FROM Teacher WHERE TeacherId = s.TeacherId
);
Result (unmatched):
Teacher | Subject
Mr. Sharma | NULL
NULL | Hindi
UNION shows unmatched from both sides.
Example 6: Combine Different Exam Types
Get all exam results across exam types:
SELECT
s.Name AS Student,
'Unit Test' AS ExamType,
r.MarksObtained
FROM Student s
INNER JOIN ExamResult r ON s.StudentId = r.StudentId
INNER JOIN Exam e ON r.ExamId = e.ExamId
WHERE e.ExamType = 'UnitTest'
UNION ALL
SELECT
s.Name AS Student,
'Final' AS ExamType,
r.MarksObtained
FROM Student s
INNER JOIN ExamResult r ON s.StudentId = r.StudentId
INNER JOIN Exam e ON r.ExamId = e.ExamId
WHERE e.ExamType = 'Final'
ORDER BY ExamType, MarksObtained DESC;
Result (all exam results):
Student | ExamType | MarksObtained
Ravi Kumar | Final | 92
Priya Sharma| Final | 88
Arjun Reddy | Unit Test | 85
UNION ALL keeps duplicates (same student in both exam types).
UNION vs JOIN Comparison
UNION (vertically stacks):
SELECT StudentId, Name FROM Student
UNION
SELECT TeacherId, Name FROM Teacher;
-- Combines rows from 2 tables (different schemas, but same columns)
JOIN (horizontally combines):
SELECT s.Name, r.MarksObtained FROM Student s
INNER JOIN ExamResult r ON s.StudentId = r.StudentId;
-- Adds columns from 2 tables
When use UNION:
- Combining same structure, different tables (students + teachers)
- Stacking filtered results
- Unmatched rows from both sides
When use JOIN:
- Getting related data from multiple tables
- Adding detail columns
- Filtering by relationships
Common UNION Mistakes
Mistake 1: Column count mismatch
Wrong:
SELECT Name, ClassName FROM Student
UNION
SELECT Name FROM Teacher;
-- ERROR: 2 columns vs 1 column
Result: Column count mismatch error.
Fix: Match column count:
SELECT Name, ClassName FROM Student
UNION
SELECT Name, Qualification FROM Teacher;
Mistake 2: Column type mismatch
Wrong:
SELECT Name, ClassId FROM Student
UNION
SELECT Name, Qualification FROM Teacher;
-- ClassId is INT, Qualification is VARCHAR
Result: Type conversion error or wrong data.
Fix: Cast to matching type:
SELECT Name, CAST(ClassId AS VARCHAR) FROM Student
UNION
SELECT Name, Qualification FROM Teacher;
Mistake 3: Forgetting duplicates with UNION
Wrong:
SELECT StudentId FROM ExamResult WHERE MarksObtained > 80
UNION
SELECT StudentId FROM ExamResult WHERE MarksObtained > 75;
-- Student 1: 92 marks appears in both results
-- UNION removes duplicate
-- Gets 5 unique students, loses duplicate
Result: Unexpected row count (fewer rows than expected).
Fix: Use UNION ALL if duplicates needed:
SELECT StudentId FROM ExamResult WHERE MarksObtained > 80
UNION ALL
SELECT StudentId FROM ExamResult WHERE MarksObtained > 75;
-- Both occurrences kept
Mistake 4: ORDER BY only on last query
Wrong:
SELECT Name FROM Student ORDER BY Name
UNION
SELECT Name FROM Teacher;
-- ORDER BY applies to Student only
Result: Unpredictable final order.
Fix: ORDER BY after UNION:
SELECT Name FROM Student
UNION
SELECT Name FROM Teacher
ORDER BY Name;
Mistake 5: Performance -- UNION with large tables
Wrong:
SELECT * FROM Student
UNION
SELECT * FROM Teacher;
-- Both tables have 1M rows
-- UNION removes duplicates = scan + sort both = slow
Result: Slow query, high CPU.
Fix: Use UNION ALL if duplicates acceptable:
SELECT * FROM Student
UNION ALL
SELECT * FROM Teacher;
-- Skip deduplication step, faster
Best Practices for UNION
- Match column count and types -- Exactly
- Use UNION ALL for performance -- If duplicates acceptable
- ORDER BY after UNION -- Applies to final result
- Use meaningful column names -- First SELECT determines names
- **Avoid UNION with SELECT * ** -- Explicit columns clearer
- Test row counts -- Verify expected duplicates removed/kept
- Consider derived table for complex logic -- If many UNIONs, use subquery
UNION: Removes duplicate rows.
SELECT Name FROM Student
UNION
SELECT Name FROM Teacher;
-- If 'Kumar' appears in both, shown once
UNION ALL: Keeps all rows including duplicates.
SELECT Name FROM Student
UNION ALL
SELECT Name FROM Teacher;
-- If 'Kumar' appears in both, shown twice
Performance: UNION ALL faster (skip deduplication).
Technically yes, but columns must match:
SELECT StudentId AS PersonId, Name FROM Student
UNION
SELECT TeacherId AS PersonId, Name FROM Teacher;
Different tables (Student vs Teacher), but SELECT returns same columns (PersonId, Name).
Rule: Column count and types match. Names from first SELECT.
UNION: Stack rows (different queries, same structure).
-- All people report
SELECT Name, 'Student' FROM Student
UNION
SELECT Name, 'Teacher' FROM Teacher;
JOIN: Add columns from related tables.
-- Student with exam results
SELECT s.Name, r.MarksObtained FROM Student s
JOIN ExamResult r ON s.StudentId = r.StudentId;
Use UNION for vertical stacking, JOIN for horizontal combining.
No, duplicates within query shown:
SELECT StudentId FROM ExamResult WHERE MarksObtained > 80;
-- Same student appears multiple times (multiple exams)
-- All rows shown (no deduplication within query)
UNION removes between queries:
SELECT StudentId FROM ExamResult WHERE MarksObtained > 80
UNION
SELECT StudentId FROM ExamResult WHERE MarksObtained > 75;
-- Student appearing in both conditions shown once
UNION deduplicates across queries only.
Not per query:
SELECT Name FROM Student ORDER BY Name -- Wrong: ORDER BY not allowed here
UNION
SELECT Name FROM Teacher;
Order final result only:
SELECT Name FROM Student
UNION
SELECT Name FROM Teacher
ORDER BY Name;
ORDER BY after UNION applies to combined result.
Find teachers without subjects AND subjects without teachers:
SELECT t.Name, NULL FROM Teacher t
WHERE NOT EXISTS (SELECT 1 FROM Subject WHERE TeacherId = t.TeacherId)
UNION
SELECT NULL, s.Name FROM Subject s
WHERE NOT EXISTS (SELECT 1 FROM Teacher WHERE TeacherId = s.TeacherId);
Alternative to FULL OUTER JOIN. Clearer intent sometimes.
Use ChatGPT, Claude, or Copilot to go deeper on UNION and UNION ALL in SQL Server. Try these prompts:
"Explain UNION: combine students and teachers into one list""What's the difference between UNION and UNION ALL?""Show UNION with 3 tables: students, teachers, staff""How do I use UNION to find unmatched records?""Quiz me: ask 5 questions about UNION, column matching, duplicates"
💡 Tip: After reading this article, paste your own code into AI and ask "What could go wrong here and why?" — fastest way to find edge cases and deepen understanding.
Next Article
20. GROUP BY & HAVING -- Grouping and Filtering Aggregates ->