简体   繁体   English

SQL中同一行的列值中第二高的值

[英]Second highest value among column values of same row in SQL

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. 使用CASE表达式来告诉您在GREATEST()调用中省略哪个得分。

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() : 和一个没有CASE的变体,同时使用GREATEST()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'. 如果绑定分数,此解决方案将选择具有较低“score_no”的分数。

Assuming no ties, you can use a big case expression: 假设没有关系,您可以使用大case表达式:

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). 我怀疑你应该有一个每个idscore一行的表(也许是一个score号)。 This is usually easier to manipulate in SQL. 这通常更容易在SQL中操作。

Using UNPIVOT try this query 使用UNPIVOT尝试此查询

    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: 结果:

在此输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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