I have 2 tables looks like this:
student_info:
| student_id | major |
|------------|-------|
| 1001 | CS |
| 1002 | CS |
| 1003 | CS |
| 1004 | CS |
| 1005 | BI |
student_grade:
| student_id | course | semester | grade |
|------------|--------|-------------|-------|
| 1001 | CS.201 | 2016.Spring | 100 |
| 1001 | CS.202 | 2016.Fall | 90 |
| 1001 | EE.201 | 2016.Spring | 90 |
| 1002 | CS.201 | 2016.Spring | 70 |
| 1002 | CS.202 | 2016.Fall | 70 |
| 1003 | CS.201 | 2016.Spring | 99 |
| 1003 | EE.201 | 2016.Fall | 90 |
| 1003 | CS.202 | 2016.Fall | 90 |
| 1004 | CS.201 | 2016.Spring | 99 |
| 1004 | BI.202 | 2016.Fall | 80 |
| 1005 | CS.201 | 2017.Spring | 100 |
Now I want to select top 2 students major in CS
grade of CS.201
in 2016.Spring
, so the results may looks like this:
| student_id | major | semester | course | grade |
|------------|-------|-------------|--------|-------|
| 1001 | CS | 2016.Spring | CS.201 | 100 |
| 1003 | CS | 2016.Spring | CS.201 | 99 |
| 1004 | CS | 2016.Spring | CS.201 | 99 |
Note that since there're 2 students who got 99
in CS.201
, so we want all 3 records (not just using limit(2)
).
The database is MySQL.
My sql script look like :
SELECT student_info.student_id,
student_info.major,
student_grade.semester,
student_grade.course,
student_grade.grade
FROM student_info, student_grade
WHERE student_info.major = 'CS'
AND student_info.student_id = student_grade.student_id
AND student_grade.semester = '2016.Spring'
AND student_grade.course = 'CS.201'
ORDER BY student_grade.grade DESC
LIMIT 2
The question need to use DENSE_RANK
function,unfortunately DENSE_RANK
function only support version higher than MySQL 8.0 .
You need to make the rank
on student_grade
,so you can write subquery to create rank result set, then join
on student_info
SELECT b.student_id,
b.major,
a.semester,
a.course,
a.grade
FROM (SELECT student_id,
grade,
semester,
course,
@prev := @curr,
@curr := grade,
@rank := IF(@prev = @curr, @rank, @rank + 1) AS rank
FROM student_grade,
(SELECT @curr := NULL,
@prev := NULL,
@rank := 0) s
WHERE course = 'CS.201'
AND semester = '2016.Spring'
ORDER BY grade DESC) a
INNER JOIN student_info b
ON a.student_id = b.student_id
WHERE a.rank <= 2
AND b.major = 'CS'
sqlfiddle: https://www.db-fiddle.com/f/tkU4UfRE3AZziiEn4HiLwF/0
Explanation:
@prev := @curr
let @curr
be previous grade @curr := grade
set current grade in @curr variable @rank := IF(@prev = @curr, @rank, @rank+1) AS rank
to check @prev
variable and @curr
variable are the same.if they are same used same rank
otherwise rank + 1
You can try mysql window function
with DENSE_RANK()
. You can refer documentation here .
SELECT * FROM
(
SELECT
a.*,
DENSE_RANK() OVER w AS 'rank'
FROM
(
SELECT
g.student_id,
i.major,
g.course,
g.semester,
g.grade
FROM
student_grade g
JOIN student_info i
ON i.student_id = g.student_id
WHERE i.major = 'CS'
AND g.semester = '2016.Spring'
AND g.course = 'CS.201'
) a
WINDOW w AS (ORDER BY a.grade DESC)
) b
WHERE b.rank <= 2;
Hope this help, good luck!
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.