Loading learning content...
In the real world, database queries are rarely as simple as "find X that satisfies all Y." Real business questions involve multiple conditions, varying contexts, dynamic requirements, and combined operations.
Consider these progressively complex queries:
This page explores how to compose division with other operations to answer sophisticated real-world questions.
By the end of this page, you'll be able to combine division with selection, join, union, and other operators. You'll understand correlated division, conditional requirements, and multi-level 'for all' queries—the patterns that distinguish experts from beginners.
The most common composition is applying selection before or after division. The order matters significantly for both semantics and performance.
Tables:
- Enrolled(StudentID, CourseID)
- Students(StudentID, Year, Major)
- Courses(CourseID, Level, Department)
Goal: Seniors enrolled in ALL CS courses at 400+ level-- Step 1: Get senior student IDs
SeniorStudents = σ_Year='Senior'(Students)
-- Step 2: Get advanced CS course IDs
AdvancedCS = π_CourseID(σ_Level>=400 ∧ Department='CS'(Courses))
-- Step 3: Filter enrollments to only seniors
SeniorEnrollments = Enrolled ⋈ SeniorStudents
-- Step 4: Divide to find seniors with all advanced CS courses
Result = π_StudentID,CourseID(SeniorEnrollments) ÷ AdvancedCS1234567891011121314151617181920
-- Find senior students enrolled in all advanced CS coursesWITH SeniorStudents AS ( SELECT StudentID FROM Students WHERE Year = 'Senior'),AdvancedCSCourses AS ( SELECT CourseID FROM Courses WHERE Department = 'CS' AND Level >= 400),SeniorEnrollments AS ( SELECT e.StudentID, e.CourseID FROM Enrolled e INNER JOIN SeniorStudents s ON e.StudentID = s.StudentID)SELECT se.StudentIDFROM SeniorEnrollments seWHERE se.CourseID IN (SELECT CourseID FROM AdvancedCSCourses)GROUP BY se.StudentIDHAVING COUNT(DISTINCT se.CourseID) = ( SELECT COUNT(*) FROM AdvancedCSCourses);Joining enables enriching division results or creating complex pairing relationships. This is especially useful when requirements span multiple tables.
Tables:
- Students(StudentID, DeptID)
- Enrolled(StudentID, CourseID)
- Courses(CourseID, DeptID)
Goal: Each student must have taken all courses from THEIR department-- This is a CORRELATED division - requirements differ per student
For each student S:
RequiredCourses_S = π_CourseID(σ_DeptID=S.DeptID(Courses))
Check if S has all courses in RequiredCourses_S
-- Relational Algebra (conceptual):
Result = { s.StudentID | s ∈ Students ∧
(π_CourseID(σ_SID=s.SID(Enrolled)) ⊇
π_CourseID(σ_DeptID=s.DeptID(Courses))) }123456789101112131415161718192021222324252627
-- Students who have taken ALL courses in their department-- Each student's requirements = courses offered by their department SELECT s.StudentIDFROM Students sWHERE NOT EXISTS ( -- Find any course in student's department they haven't taken SELECT c.CourseID FROM Courses c WHERE c.DeptID = s.DeptID AND NOT EXISTS ( -- Check if student has taken this course SELECT 1 FROM Enrolled e WHERE e.StudentID = s.StudentID AND e.CourseID = c.CourseID )); -- Alternative using counting (per student):SELECT s.StudentIDFROM Students sINNER JOIN Enrolled e ON s.StudentID = e.StudentIDINNER JOIN Courses c ON e.CourseID = c.CourseID AND c.DeptID = s.DeptIDGROUP BY s.StudentIDHAVING COUNT(DISTINCT e.CourseID) = ( SELECT COUNT(*) FROM Courses c2 WHERE c2.DeptID = s.DeptID);When requirements vary per candidate, you're doing correlated division. The NOT EXISTS approach handles this naturally since the inner query references the outer candidate.
Sometimes you need to satisfy multiple independent requirement sets. This requires combining several division operations.
Question: "Which students are enrolled in all CS courses AND all Math courses?"
Structure: (Enrolled ÷ CS_Courses) ∩ (Enrolled ÷ Math_Courses)
Meaning: Must satisfy BOTH requirement sets completely.
123456789101112131415161718
-- Students enrolled in ALL CS courses AND ALL Math coursesSELECT StudentIDFROM EnrolledWHERE CourseID IN (SELECT CourseID FROM Courses WHERE Dept = 'CS')GROUP BY StudentIDHAVING COUNT(DISTINCT CourseID) = ( SELECT COUNT(*) FROM Courses WHERE Dept = 'CS') INTERSECT SELECT StudentID FROM EnrolledWHERE CourseID IN (SELECT CourseID FROM Courses WHERE Dept = 'Math')GROUP BY StudentIDHAVING COUNT(DISTINCT CourseID) = ( SELECT COUNT(*) FROM Courses WHERE Dept = 'Math');Be precise about what's being combined: (R ÷ S₁) ∩ (R ÷ S₂) ≠ R ÷ (S₁ ∪ S₂) ≠ R ÷ (S₁ ∩ S₂). Each has different semantics. Draw out the logic carefully.
Complex queries sometimes require nested "for all" conditions—universality at multiple levels.
Tables:
- Teaches(ProfessorID, StudentID) -- professor has taught student
- Enrolled(StudentID, CourseID)
- CSCourses(CourseID)
Step 1: Find students enrolled in all CS courses
Step 2: Find professors who have taught ALL of those studentsRelational Algebra:
-- First division: students with all CS courses
AllCSStudents = Enrolled ÷ CSCourses
-- Second division: professors who taught ALL such students
Result = Teaches ÷ AllCSStudents12345678910111213141516171819202122232425262728293031323334353637
-- Professors who have taught ALL students enrolled in all CS courses -- Step 1: Students enrolled in all CS coursesWITH EliteCSStudents AS ( SELECT e.StudentID FROM Enrolled e WHERE e.CourseID IN (SELECT CourseID FROM CSCourses) GROUP BY e.StudentID HAVING COUNT(DISTINCT e.CourseID) = (SELECT COUNT(*) FROM CSCourses))-- Step 2: Professors who've taught ALL elite studentsSELECT t.ProfessorIDFROM Teaches tWHERE t.StudentID IN (SELECT StudentID FROM EliteCSStudents)GROUP BY t.ProfessorIDHAVING COUNT(DISTINCT t.StudentID) = (SELECT COUNT(*) FROM EliteCSStudents); -- Alternative: Using NOT EXISTS (nested)SELECT DISTINCT t1.ProfessorIDFROM Teaches t1WHERE NOT EXISTS ( -- Find any elite student this professor hasn't taught SELECT es.StudentID FROM ( -- Elite students subquery SELECT e.StudentID FROM Enrolled e WHERE e.CourseID IN (SELECT CourseID FROM CSCourses) GROUP BY e.StudentID HAVING COUNT(DISTINCT e.CourseID) = (SELECT COUNT(*) FROM CSCourses) ) es WHERE NOT EXISTS ( SELECT 1 FROM Teaches t2 WHERE t2.ProfessorID = t1.ProfessorID AND t2.StudentID = es.StudentID ));The Pattern:
∀x ∈ {y | ∀z.P(y,z)} . Q(a,x)
Inner level: "For all z, P(y,z)" defines a set of y's Outer level: "For all such y's, Q(a,y) holds" defines the result a's
This translates to:
Another complex pattern: "Find X that satisfies all requirements for AT LEAST ONE of several categories." This combines existential (∃) and universal (∀) quantification.
Tables:
- Students(StudentID, Name)
- Completed(StudentID, CourseID)
- DegreeRequirements(DegreeID, CourseID)
- Degrees(DegreeID, Name)
Goal: Student qualifies for ≥1 degree (complete requirements for at least one)Logical form:
∃d ∈ Degrees: (∀c ∈ Requirements(d): Completed(s, c))
English: There EXISTS a degree for which the student has completed ALL requirements.12345678910111213141516171819202122232425262728293031323334353637
-- Students who qualify for at least one degree-- (have completed ALL requirements for at least one degree) SELECT DISTINCT StudentIDFROM Students sWHERE EXISTS ( -- There exists a degree... SELECT d.DegreeID FROM Degrees d WHERE NOT EXISTS ( -- ...for which NO requirement is unmet SELECT dr.CourseID FROM DegreeRequirements dr WHERE dr.DegreeID = d.DegreeID AND NOT EXISTS ( -- Requirement is unmet if not in Completed SELECT 1 FROM Completed c WHERE c.StudentID = s.StudentID AND c.CourseID = dr.CourseID ) )); -- Alternative: Using aggregation and ANYWITH DegreeCompletionCounts AS ( SELECT c.StudentID, dr.DegreeID, COUNT(DISTINCT c.CourseID) as completed, COUNT(DISTINCT dr.CourseID) as required FROM Completed c INNER JOIN DegreeRequirements dr ON c.CourseID = dr.CourseID GROUP BY c.StudentID, dr.DegreeID)SELECT DISTINCT StudentIDFROM DegreeCompletionCountsWHERE completed = required;∃x.∀y.P means 'there exists an x such that for all y, P holds'—find any witness satisfying universal condition. This is weaker (easier to satisfy) than ∀x.∀y.P (every x must satisfy universal condition for all y).
Sometimes the requirement set depends on properties of the candidate. This creates "conditional" or "contextual" division patterns.
1234567891011121314151617181920212223242526272829303132333435
-- Different graduation requirements by student year-- Seniors: must complete CoreCourses + AdvancedCourses-- Juniors: must complete only CoreCourses -- Approach: UNION of conditional divisions -- Seniors who've completed all senior requirementsSELECT s.StudentID, 'Senior' as YearFROM Students sINNER JOIN Completed c ON s.StudentID = c.StudentIDWHERE s.Year = 'Senior' AND c.CourseID IN ( SELECT CourseID FROM CoreCourses UNION SELECT CourseID FROM AdvancedCourses )GROUP BY s.StudentIDHAVING COUNT(DISTINCT c.CourseID) = ( SELECT COUNT(*) FROM CoreCourses UNION SELECT COUNT(*) FROM AdvancedCourses) UNION -- Juniors who've completed all junior requirements SELECT s.StudentID, 'Junior' as YearFROM Students sINNER JOIN Completed c ON s.StudentID = c.StudentIDWHERE s.Year = 'Junior' AND c.CourseID IN (SELECT CourseID FROM CoreCourses)GROUP BY s.StudentIDHAVING COUNT(DISTINCT c.CourseID) = ( SELECT COUNT(*) FROM CoreCourses);General Pattern for Conditional Division:
-- When requirements depend on candidate properties
SELECT candidate_id
FROM Candidates c
WHERE (
-- Condition 1 requirements
c.property = 'Value1'
AND /* division check for Requirement Set 1 */
) OR (
-- Condition 2 requirements
c.property = 'Value2'
AND /* division check for Requirement Set 2 */
);
Or more elegantly with CASE-based logic in modern SQL systems.
Sometimes you want the opposite of division: find candidates who are MISSING at least one requirement. This "anti-division" pattern is equally useful.
Anti-Division:
Anti-Division(R, S) = π_A(R) − (R ÷ S)
Returns A-values that have at least one missing B-value from S.
Use Cases:
123456789101112131415161718192021222324252627282930313233343536373839
-- Students NOT ready to graduate (missing at least one required course) -- Method 1: Simple—everyone NOT in the division resultSELECT DISTINCT e.StudentIDFROM Enrolled eWHERE e.StudentID NOT IN ( -- The division: students with all requirements SELECT e2.StudentID FROM Enrolled e2 WHERE e2.CourseID IN (SELECT CourseID FROM RequiredCourses) GROUP BY e2.StudentID HAVING COUNT(DISTINCT e2.CourseID) = ( SELECT COUNT(*) FROM RequiredCourses )); -- Method 2: Using EXISTS to find at least one gapSELECT DISTINCT e.StudentIDFROM Enrolled eWHERE EXISTS ( SELECT rc.CourseID FROM RequiredCourses rc WHERE NOT EXISTS ( SELECT 1 FROM Enrolled e2 WHERE e2.StudentID = e.StudentID AND e2.CourseID = rc.CourseID )); -- Bonus: Show WHAT'S missing for each studentSELECT e.StudentID, rc.CourseID as MissingCourseFROM (SELECT DISTINCT StudentID FROM Enrolled) eCROSS JOIN RequiredCourses rcWHERE NOT EXISTS ( SELECT 1 FROM Enrolled e2 WHERE e2.StudentID = e.StudentID AND e2.CourseID = rc.CourseID)ORDER BY e.StudentID, rc.CourseID;The 'show what's missing' query is invaluable for user-facing applications. Instead of just flagging incomplete status, you can tell users exactly which requirements they still need to meet.
Let's tie it all together with a complex, realistic scenario that combines multiple patterns.
Requirements:
1. Each role has required certifications
2. Employees have earned various certifications (with expiry dates)
3. Find employees who are COMPLIANT (have all current certs for their role)
4. Find employees who are NON-COMPLIANT (missing ≥1)
5. For non-compliant: show what's missing
6. Show compliance by departmentTables:
- Employees(EmployeeID, Name, RoleID, DepartmentID)
- Roles(RoleID, Name)
- RoleCertifications(RoleID, CertificationID)
- EmployeeCerts(EmployeeID, CertificationID, ExpiryDate)
- Certifications(CertificationID, Name)12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
-- Part 1: Current (non-expired) employee certificationsWITH CurrentCerts AS ( SELECT EmployeeID, CertificationID FROM EmployeeCerts WHERE ExpiryDate > CURRENT_DATE), -- Part 2: Employees who are COMPLIANT (have all role certs)CompliantEmployees AS ( SELECT e.EmployeeID FROM Employees e WHERE NOT EXISTS ( -- Find any required cert this employee lacks SELECT rc.CertificationID FROM RoleCertifications rc WHERE rc.RoleID = e.RoleID AND NOT EXISTS ( SELECT 1 FROM CurrentCerts cc WHERE cc.EmployeeID = e.EmployeeID AND cc.CertificationID = rc.CertificationID ) )), -- Part 3: Non-compliant employees with missing certsNonCompliantWithGaps AS ( SELECT e.EmployeeID, e.Name, e.DepartmentID, rc.CertificationID as MissingCertID FROM Employees e INNER JOIN RoleCertifications rc ON e.RoleID = rc.RoleID WHERE e.EmployeeID NOT IN (SELECT EmployeeID FROM CompliantEmployees) AND NOT EXISTS ( SELECT 1 FROM CurrentCerts cc WHERE cc.EmployeeID = e.EmployeeID AND cc.CertificationID = rc.CertificationID )) -- Final Report: Compliance by departmentSELECT d.Name as Department, COUNT(DISTINCT ce.EmployeeID) as CompliantCount, (SELECT COUNT(*) FROM Employees e2 WHERE e2.DepartmentID = d.DepartmentID) - COUNT(DISTINCT ce.EmployeeID) as NonCompliantCount, ROUND(100.0 * COUNT(DISTINCT ce.EmployeeID) / (SELECT COUNT(*) FROM Employees e3 WHERE e3.DepartmentID = d.DepartmentID), 1 ) as ComplianceRateFROM Departments dLEFT JOIN Employees emp ON d.DepartmentID = emp.DepartmentIDLEFT JOIN CompliantEmployees ce ON emp.EmployeeID = ce.EmployeeIDGROUP BY d.DepartmentID, d.NameORDER BY ComplianceRate DESC;We've explored how division combines with other operations to solve sophisticated real-world problems. Here are the key patterns:
| Pattern | SQL Approach | Use Case |
|---|---|---|
| R ÷ (S₁ ∪ S₂) | Combined WHERE clause | All requirements from either |
| (R ÷ S₁) ∩ (R ÷ S₂) | INTERSECT of two divisions | Meet both requirement sets |
| ∃x.∀y.P(x,y) | EXISTS(NOT EXISTS(NOT EXISTS)) | Some category fully satisfied |
| Correlated division | Reference outer in inner | Per-entity requirements |
| Anti-division | NOT IN (division result) | Find incomplete candidates |
You have mastered the division operation in relational algebra—from conceptual foundations through practical SQL implementation to complex multi-operation queries. You can now recognize, formulate, and optimize 'for all' queries in any database context.
Reflection:
The division operator represents the full expressive power of relational algebra. By mastering division, you've completed your understanding of the core operators. You can now:
This foundation prepares you for advanced topics like query optimization, relational calculus, and the theoretical underpinnings of database query languages.