简体   繁体   中英

Making a pair in SQL query

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.

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 ie, 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

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)

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM