This problem requires finding the highest grade achieved by each student and the corresponding course ID. In case of ties in the highest grade, the course with the lowest course_id
should be selected. The result should be ordered by student_id
.
Two approaches are presented below, both using SQL:
RANK()
Window FunctionThis solution leverages the power of window functions for efficient ranking and filtering.
Approach:
Window Function: A Common Table Expression (CTE) called T
is created. Inside, the RANK()
window function is applied. RANK()
assigns a rank to each row within a partition (each student's records). The partitioning is done by student_id
, and the ordering is first by grade
in descending order (highest grade first) and then by course_id
in ascending order (lowest course ID in case of tie).
Filtering: The main query selects student_id
, course_id
, and grade
from T
, filtering only the rows where the rank (rk
) is 1. This ensures we get only the top record for each student (highest grade, lowest course_id
in case of tie).
Ordering: Finally, the result is ordered by student_id
in ascending order as required.
MySQL Code:
WITH
T AS (
SELECT
*,
RANK() OVER (
PARTITION BY student_id
ORDER BY grade DESC, course_id
) AS rk
FROM Enrollments
)
SELECT student_id, course_id, grade
FROM T
WHERE rk = 1
ORDER BY student_id;
Time Complexity: O(N log N), where N is the number of rows in the Enrollments
table. This is due to the sorting involved in the RANK()
function. The exact complexity depends on the database engine's implementation of window functions.
Space Complexity: O(N) in the worst case, due to the intermediate CTE T
potentially storing all rows. Again, the actual space usage depends on the database engine's optimization strategies.
This solution uses nested subqueries to achieve the same result.
Approach:
Inner Subquery: The inner subquery finds the maximum grade for each student using MAX(grade)
and GROUP BY student_id
.
Outer Query: The outer query joins the Enrollments
table with the result of the inner subquery. It selects rows where the (student_id, grade)
combination matches the highest grade for each student. The MIN(course_id)
is used to select the course with the lowest ID in case of multiple courses with the highest grade.
Grouping and Ordering: The outer query then groups the results by student_id
and orders them by student_id
.
MySQL Code:
SELECT student_id, MIN(course_id) AS course_id, grade
FROM Enrollments
WHERE
(student_id, grade) IN (
SELECT student_id, MAX(grade) AS grade
FROM Enrollments
GROUP BY 1
)
GROUP BY 1
ORDER BY 1;
Time Complexity: This approach also has a time complexity of O(N log N) due to the sorting implicit in the GROUP BY
and MAX()
operations within the subqueries. The exact complexity depends on the database engine's optimization of these operations.
Space Complexity: O(N) in the worst case, as the intermediate results from subqueries could potentially store all rows. This depends again on the database optimizer.
Comparison:
Both solutions achieve the same result. The RANK()
window function approach might be considered slightly more readable and potentially more efficient in some database systems, especially for very large datasets, as it avoids the join operation used in the subquery method. However, the performance difference may be minimal in practice and depends on the specific database engine and its optimizations. The choice depends on personal preference and familiarity with SQL features.