I know how to get the top values but am having trouble with something very simple.
I have a student table. It has:
- name
- numberoflaps
- grade
I want the get a query or report that shows the top two kids with the most laps per grade.
I know how to get the top values but am having trouble with something very simple.
I have a student table. It has:
I want the get a query or report that shows the top two kids with the most laps per grade.
MySQL doesn't have any ranking functionality, but it does allow for variable creation & updating:
SELECT x.grade,
x.name,
x.numberoflaps
FROM (SELECT s.grade,
s.name,
s.numberoflaps,
CASE
WHEN @grade != s.grade THEN @rownum := 1
ELSE @rownum := @rownum + 1
END AS rank,
@grade := s.grade
FROM STUDENTS s,
(SELECT @rownum := 0, @grade := NULL) r
ORDER BY s.grade, s.numberoflaps DESC) x
WHERE x.rank <= 2
ORDER BY x.grade, x.rank
The ORDER BY
in the subquery is important, otherwise the ranking won't be properly performed.
Using a CTE:
WITH laps AS (
SELECT s.grade,
s.name,
s.numberoflaps,
ROW_NUMBER() OVER (PARTITION BY grade ORDER BY numberoflaps DESC) AS rank
FROM STUDENTS s)
SELECT l.grade,
l.name,
l.numberoflaps
FROM laps l
WHERE l.rank <= 2
ORDER BY l.grade, l.numberoflaps DESC
Non-CTE equivalent:
SELECT l.grade,
l.name,
l.numberoflaps
FROM (SELECT s.grade,
s.name,
s.numberoflaps,
ROW_NUMBER() OVER (PARTITION BY grade ORDER BY numberoflaps DESC) AS rank
FROM STUDENTS s) l
WHERE l.rank <= 2
ORDER BY l.grade, l.numberoflaps DESC
Oracle gained ranking functionality in 9i; for SQL Server it was 2005.
SQL Server 2005+ version would look like this:
;WITH Laps_CTE AS
(
SELECT
grade, name, numberoflaps,
ROW_NUMBER() OVER (
PARTITION BY grade
ORDER BY numberoflaps DESC
) AS RowNum
FROM students
)
SELECT grade, name, numberoflaps
FROM Laps_CTE
WHERE RowNum <= 2
If that's not your dialect, please let us know what is.