Reputation: 896
I recently started picking up on SQL, and I am curious about the following
There's a table, T, containing the following two columns:
student name, score
There is an even number of rows in the table, let's call that number 2N
Is there any easy way to make a new table having the following rows:
highest scorer's name, highest score, lowest scorer's name, lowest score
2nd highest scorer's name, 2nd highest score, 2nd lowest scorer's name, 2nd lowest score
3rd highest scorer's name, 3rd highest score, 3rd lowest scorer's name, 3rd lowest score
.
.
.
.
.
Nth highest scorer's name, Nth highest score, Nth lowest scorer's name, Nth lowest score
So there will be N rows total.
or is this type of job not suitable in SQL?
It's easy to list the 1st to Nth highest scorer first and 1st to Nth lowest scorer next, but I wasn't sure if there's a way to join them like above nicely in SQL.
Upvotes: 0
Views: 2302
Reputation: 3781
Assuming you have the following data.
mysql> select * FROM T;
+--------------+-------+
| student_name | score |
+--------------+-------+
| student 1 | 10 |
| student 2 | 5 |
| student 3 | 1 |
+--------------+-------+
3 rows in set (0.00 sec)
You can order the table by score
ascending and descending adding a rank. Then you can join on that rank.
SELECT high.student_name, high.score, low.student_name, low.score FROM
(SELECT @n:=@n+1 AS ord, student_name, score
FROM T, (SELECT @n:=0) n
ORDER BY score DESC) AS high
JOIN
(SELECT @m:=@m+1 AS ord, student_name, score
FROM T, (SELECT @m:=0) m
ORDER BY score ASC) AS low
ON high.ord = low.ord
The result for this query for the given data is the following.
+--------------+-------+--------------+-------+
| student_name | score | student_name | score |
+--------------+-------+--------------+-------+
| student 1 | 10 | student 3 | 1 |
| student 2 | 5 | student 2 | 5 |
| student 3 | 1 | student 1 | 10 |
+--------------+-------+--------------+-------+
3 rows in set (0.00 sec)
Upvotes: 1
Reputation: 49260
You can calculate the row numbers both in ascending and descending order of score and join them on the condition rownumbers are equal.
SELECT X.NAME,
X.SCORE,
Y.NAME,
Y.SCORE
FROM
(SELECT NAME,SCORE,@RN_ASC:=@RN_ASC+1 AS RNUM
FROM T
CROSS JOIN (SELECT @RN_ASC:=0) R
ORDER BY SCORE) X
JOIN
(SELECT NAME,SCORE,@RN_DESC:=@RN_DESC+1 AS RNUM
FROM T
CROSS JOIN (SELECT @RN_DESC:=0) R
ORDER BY SCORE DESC) Y
ON X.RNUM = Y.RNUM AND X.SCORE>Y.SCORE
If you have odd number (n) of rows in the table the middle row ((n/2)+1 th) would be skipped.
If there can be ties in scores, use the name
column to break the tie i.e, pick one name over the other (by specifying name ascending or descending in order by
).
SELECT X.NAME,
X.SCORE,
Y.NAME,
Y.SCORE
FROM
(SELECT NAME,SCORE,@RN_ASC:=@RN_ASC+1 AS RNUM
FROM T
CROSS JOIN (SELECT @RN_ASC:=0) R
ORDER BY SCORE,NAME) X
JOIN
(SELECT NAME,SCORE,@RN_DESC:=@RN_DESC+1 AS RNUM
FROM T
CROSS JOIN (SELECT @RN_DESC:=0) R
ORDER BY SCORE DESC,NAME) Y
ON X.RNUM = Y.RNUM AND X.SCORE>Y.SCORE
Upvotes: 2