MySQL 1280.sql
WITH crossed AS (SELECT st.student_id, st.student_name, su.subject_name
FROM Students st, Subjects su) -- all combinations
SELECT c.student_id, c.student_name, c.subject_name,
COUNT(e.subject_name) AS attended_exams
FROM crossed c LEFT JOIN Examinations e
ON c.student_id = e.student_id AND c.subject_name = e.subject_name
GROUP BY c.student_id, c.subject_name
ORDER BY c.student_id, c.subject_name
Difficulty
and has an acceptance rate of about 62% (1+ million submissions).
Typical patterns to solve this problem:
- Database
AI Disclaimer
However, two years later I set up this website and used various AI tools to generate most of the walkthrough / explanations below.
See this dedicated page for more details.
Code Walkthrough
Overview
The script builds a complete matrix of every student paired with every subject and then determines how many examinations each student has attended for each subject. The result lists every student-subject combination, even when no examinations exist, and shows a count of attended exams that is zero in those cases. The query is structured with a common table expression (CTE) that materializes the Cartesian product, followed by a left outer join to the examinations table, aggregation, and final ordering.
Construction of the Cartesian Product
The first step creates a CTE named crossed that enumerates all possible student-subject pairs.
WITH crossed AS (
SELECT st.student_id,
st.student_name,
su.subject_name
FROM Students st,
Subjects su
)
By selecting from both Students and Subjects without a join condition, the query generates every combination of rows from the two tables. This guarantees that each student appears once for each subject, establishing the foundation for a complete attendance matrix.
Joining Examinations and Counting Attendance
The next phase left-joins the crossed CTE with the Examinations table on both student and subject identifiers, then aggregates the matches.
SELECT c.student_id,
c.student_name,
c.subject_name,
COUNT(e.subject_name) AS attended_exams
FROM crossed c
LEFT JOIN Examinations e
ON c.student_id = e.student_id
AND c.subject_name = e.subject_name
GROUP BY c.student_id,
c.subject_name
ORDER BY c.student_id,
c.subject_name;
The left outer join preserves every row from crossed. When a matching examination record exists, the join produces a non-null e.subject_name; otherwise the columns from e are null. The COUNT(e.subject_name) expression counts only non-null values, so rows without matching examinations contribute a count of zero.
Edge Cases Handled by the Query
When a student has never taken an exam for a particular subject, the left join yields a row where all Examinations columns are null. Because COUNT ignores nulls, the attended_exams column correctly reports zero. Similarly, if a subject has never been examined for any student, the Cartesian product still creates rows for that subject, and each row will again show a zero count. The query also gracefully handles students who have no examinations at all; they appear once per subject with a zero count. The grouping clause includes only student_id and subject_name, which means that multiple rows for the same student-subject pair (e.g., multiple exam attempts) are collapsed into a single aggregated result.
Performance Optimizations Observed
The use of a CTE isolates the Cartesian product computation, allowing the database engine to materialize it once and reuse it for the subsequent join. This can reduce repeated evaluation of the cross-join logic. The left join is performed on indexed columns (student_id and subject_name), which enables the optimizer to use index lookups rather than full scans of the Examinations table for each pair. Counting only the non-null e.subject_name avoids an extra CASE expression and leverages the built-in null-aware aggregation. Finally, the ORDER BY clause follows the same columns used in the GROUP BY, allowing the engine to produce sorted output without an additional sorting pass if the grouping operation already yields rows in the required order.
ELI5 - Simplified Explanation
Imagine every student needs to take every possible test, even if they have not actually walked into the classroom to take one yet. First, the code creates a very long list that pairs every student with every single subject so that nobody is left out. Think of this like making a giant chart of every person and every class.
After that list is ready, the code looks at the real records of students who actually went to take their exams. It matches those real test records up with the giant chart from before. Because some students might have skipped a test, the code keeps them on the list anyway and marks that they have attended zero exams for that subject. Finally, the computer counts how many times each student showed up for each specific subject and organizes the names and classes into a neat order so everything is easy to read.
Code Quality
Complexity Analysis
Other Solutions
Obviously, I did that after I solved the problem myself.
In general, AlgoMonster and WalkCCC solutions are high-quality and always worth a look.
I haven't checked most of the other solutions, but they might be helpful as well.
And of course, the LeetCode forum is always a good place (or even the best) to look for alternative approaches.
(click on a column header to sort the table)
| author | ||||||
|---|---|---|---|---|---|---|
| author | solutions | |||||
| www | AlgoMonster | C++ | Java | Python | TS | |
| WalkCCC | SQL | |||||
| leetcode.ca | SQL | |||||
| Progiez | C++ | Java | Python | |||
| github | suxrobGM | SQL | ||||
| AlgoMonster | C++, Python, Java, TypeScript | |||||
| WalkCCC | SQL | |||||
| leetcode.ca | SQL | |||||
| Progiez | C++, Java, Python | |||||
| suxrobGM | SQL |
Videos
Solved On The Same Day
- problem 415: Add Strings
- problem 463: Island Perimeter
- problem 541: Reverse String II
- problem 1211: Queries Quality and Percentage
- problem 1251: Average Selling Price
- problem 1327: List the Products Ordered in a Period
- problem 1378: Replace Employee ID With The Unique Identifier
- problem 1407: Top Travellers
- problem 1484: Group Sold Products By The Date
- problem 1517: Find Users With Valid E-Mails
- problem 1527: Patients With a Condition
- problem 1581: Customer Who Visited but Did Not Make Any Transactions
- problem 1587: Bank Account Summary II
- problem 1633: Percentage of Users Attended a Contest
- problem 1661: Average Time of Process per Machine
- problem 1667: Fix Names in a Table
- problem 1683: Invalid Tweets
- problem 1693: Daily Leads and Partners
- problem 1729: Find Followers Count
- problem 1731: The Number of Employees Which Report to Each Employee
- problem 1741: Find Total Time Spent by Each Employee
- problem 1757: Recyclable and Low Fat Products
- problem 1789: Primary Department for Each Employee
- problem 1795: Rearrange Products Table
- problem 1873: Calculate Special Bonus
- problem 1890: The Latest Login in 2020
- problem 1965: Employees With Missing Information
- problem 1978: Employees Whose Manager Left the Company
- problem 2356: Number of Unique Subjects Taught by Each Teacher
- problem 166: Fraction to Recurring Decimal
- problem 223: Rectangle Area
- problem 240: Search a 2D Matrix II
- problem 318: Maximum Product of Word Lengths
- problem 357: Count Numbers with Unique Digits
- problem 394: Decode String
- problem 1158: Market Analysis I
- problem 1341: Movie Rating
- problem 1492: The kth Factor of n
- problem 1498: Number of Subsequences That Satisfy the Given Sum Condition
- problem 1907: Count Salary Categories
- problem 1934: Confirmation Rate
- problem 2405: Optimal Partition of String
Extra
- Tech Stack - my development environment and tools
- AI - how AI helped me create this website (NOT solving the problems)
- Progress - progression over time
- Quality - code quality