Sample data:
id score1 score2 score3 score4
1 10 05 30 50
2 05 15 10 00
3 25 10 05 15
Expected result set:
id col_value
1 30
2 10
3 15
Use a CASE
expression to tell which score to omit in your GREATEST()
call.
SELECT id,
CASE GREATEST(score1, score2, score3, score4)
WHEN score1 THEN GREATEST(score2, score3, score4)
WHEN score2 THEN GREATEST(score1, score3, score4)
WHEN score3 THEN GREATEST(score1, score2, score4)
ELSE GREATEST(score1, score2, score3)
END AS col_value
FROM your_table ;
This solution generalizes easily to any number of columns.
and a variation without CASE
, using both GREATEST()
and LEAST()
:
SELECT id,
LEAST(
GREATEST(score1, score2, score3),
GREATEST(score2, score3, score4),
GREATEST(score3, score4, score1),
GREATEST(score4, score1, score2)
) AS col_value
FROM your_table ;
Consider the following, which generalizes yet more easily still:
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id INT NOT NULL
,score_no INT NOT NULL
,score INT NOT NULL
,PRIMARY KEY(id,score_no)
);
INSERT INTO my_table VALUES
(1, 1 ,10),
(1 ,2 ,05),
(1 ,3 ,30),
(1 ,4 ,50),
(2 ,1 ,05),
(2 ,2 ,15),
(2 ,3 ,10),
(2 ,4 ,00),
(3 ,1 ,25),
(3 ,2 ,10),
(3 ,3 ,05),
(3 ,4 ,15);
SELECT id
, score_no
, score
FROM
( SELECT x.*
, CASE WHEN @prev=id THEN @i:=@i+1 ELSE @i:=1 END rank
, @prev:=id
FROM my_table x
, (SELECT @prev:=null,@i:=0) vars
ORDER
BY id
, score DESC
, score_no
) a
WHERE rank = 2;
+----+----------+-------+
| id | score_no | score |
+----+----------+-------+
| 1 | 3 | 30 |
| 2 | 3 | 10 |
| 3 | 4 | 15 |
+----+----------+-------+
In the event of tied scores, this solution picks the one with the lower 'score_no'.
Assuming no ties, you can use a big case
expression:
select t.*,
(case when score1 > score2 and score1 > score3 and score1 < score 4 then score1
when score1 > score2 and score1 < score3 and score1 > score 4 then score1
when score1 < score2 and score1 > score3 and score1 > score 4 then score1
when score2 > score1 and score2 > score3 and score2 < score 4 then score2
when score2 > score1 and score2 < score3 and score2 > score 4 then score2
when score2 < score1 and score2 > score3 and score2 > score 4 then score2
. . .
end) as second_score
from t;
In general, though, this type of question suggests a problem with the data structure. I suspect that you should really have a table with one row per id
and score
(and perhaps a score
number). This is usually easier to manipulate in SQL.
Using UNPIVOT
try this query
CREATE TABLE #my_table
(id INT NOT NULL, score1 INT NOT NULL, score2 INT NOT NULL, score3 INT NOT NULL, score4 INT NOT NULL)
INSERT INTO #my_table VALUES(1, 10, 05, 30, 50)
INSERT INTO #my_table VALUES(2, 05, 15, 10, 00)
INSERT INTO #my_table VALUES(3, 25, 10, 05, 15)
;WITH getHighestValue as (
SELECT id, Scores, ScoreText, ROW_NUMBER() OVER(PARTITION BY id ORDER BY Scores DESC) AS Ranks
FROM #my_table
UNPIVOT(
Scores for ScoreText in (score1,score2,score3,score4)
) unpiv
)
SELECT id, Scores as col_value
FROM getHighestValue
WHERE Ranks = 2
Result:
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.