Information is the oil of the 21st century, and analytics is the combustion engine.
Peter Sondergaard (Former EVP, Research & Advisory – Gartner)
Question Source: LeetCode
Solution Language: MySQL
This Q&A series will cover data questions from LeetCode and present my solutions to them. Please feel free to comment with your suggestions if you feel that these problems may be solved in a more optimized manner.
Question (LeetCode Question #1412, Level: Hard)
Table: Student
+---------------------+---------+ | Column Name | Type | +---------------------+---------+ | student_id | int | | student_name | varchar | +---------------------+---------+ student_id is the primary key for this table. student_name is the name of the student.
Table: Exam
+---------------+---------+ | Column Name | Type | +---------------+---------+ | exam_id | int | | student_id | int | | score | int | +---------------+---------+ (exam_id, student_id) is the primary key for this table. Student with student_id got score points in exam with id exam_id.
A “quiet” student is the one who took at least one exam and didn’t score neither the high score nor the low score.
Write an SQL query to report the students (student_id, student_name) being “quiet” in ALL exams.
Don’t return the student who has never taken any exam. Return the result table ordered by student_id.
The query result format is in the following example.
Student table: +-------------+---------------+ | student_id | student_name | +-------------+---------------+ | 1 | Daniel | | 2 | Jade | | 3 | Stella | | 4 | Jonathan | | 5 | Will | +-------------+---------------+ Exam table: +------------+--------------+-----------+ | exam_id | student_id | score | +------------+--------------+-----------+ | 10 | 1 | 70 | | 10 | 2 | 80 | | 10 | 3 | 90 | | 20 | 1 | 80 | | 30 | 1 | 70 | | 30 | 3 | 80 | | 30 | 4 | 90 | | 40 | 1 | 60 | | 40 | 2 | 70 | | 40 | 4 | 80 | +------------+--------------+-----------+ Result table: +-------------+---------------+ | student_id | student_name | +-------------+---------------+ | 2 | Jade | +-------------+---------------+ For exam 1: Student 1 and 3 hold the lowest and high score respectively. For exam 2: Student 1 hold both highest and lowest score. For exam 3 and 4: Studnet 1 and 4 hold the lowest and high score respectively. Student 2 and 5 have never got the highest or lowest in any of the exam. Since student 5 is not taking any exam, he is excluded from the result. So, we only return the information of Student 2.
Solution
WITH cte AS
(SELECT student_id,
score,
exam_id,
(CASE WHEN score < MAX(score) OVER (PARTITION BY exam_id)
AND score > MIN(score) OVER (PARTITION BY exam_id)
THEN 'middle'
ELSE 'highlow'
END) AS category
FROM Exam
ORDER BY student_id),
cte1 AS (SELECT student_id
FROM cte
GROUP BY student_id
HAVING SUM(CASE WHEN category = 'highlow'
THEN 1 ELSE 0
END) = 0
)
SELECT cte1.student_id, s.student_name
FROM cte1 JOIN Student s
ON cte1.student_id = s.student_id
ORDER BY cte1.student_id
Alternate Approaches…
WITH cte AS
(SELECT student_id, score, exam_id,
max(score) OVER (PARTITION BY exam_id) AS maxscore,
min(score) OVER (PARTITION BY exam_id) AS minscore
FROM Exam),
cte1 AS
(SELECT student_id
FROM cte
WHERE score = maxscore OR score = minscore
)
SELECT DISTINCT Exam.student_id, Student.student_name
FROM Exam JOIN Student
ON Exam.student_id = Student.student_id
WHERE Exam.student_id NOT IN (SELECT student_id FROM cte1)
ORDER BY Exam.student_id
WITH cte AS (SELECT student_id,
rank() OVER (PARTITION BY exam_id ORDER BY score DESC)
AS gethighest,
rank() OVER (PARTITION BY exam_id ORDER BY score ASC)
AS getlowest
FROM Exam),
cte1 AS (SELECT DISTINCT student_id,
SUM(CASE WHEN gethighest = 1
OR getlowest = 1
THEN 1
ELSE 0 END)
OVER (PARTITION BY student_id ORDER BY student_id)
AS numofhighlow
FROM cte)
SELECT cte1.student_id, student_name
FROM cte1 JOIN Student
ON cte1.student_id = Student.student_id
WHERE cte1.numofhighlow = 0