在Oracle SQL上只排除一个MIN值

时间:2014-10-18 17:30:13

标签: sql oracle top-n

我正在尝试选择列中最低值(GameScore)以外的所有值,但是当有两个最低值时,我的代码将两者都排除在外(我知道为什么会这样做,我只是不确切知道如何纠正它并包括两个最低值之一。)

代码看起来像这样:

SELECT Id, SUM(Score) / COUNT(Score) AS Score
FROM 
    (SELECT Id, Score
    FROM GameScore
    WHERE Game_No = 1
      AND Score NOT IN 
        (SELECT MIN(Score)
        FROM GameScore
        WHERE Game_No = 1
        GROUP BY Id))
 GROUP BY Id

因此,如果我从5个值中抽取,但​​其中一个行只得到3分,因为底部两个是相同的,我如何包含第4个?感谢。

2 个答案:

答案 0 :(得分:4)

为了做到这一点,你必须以某种方式将它们分开;您当前的问题是2个最低分数是相同的,因此对任一值执行的任何(in)相等操作都相同地处理另一个值。

您可以使用类似分析查询ROW_NUMBER()的内容来唯一标识行:

select id, sum(score) / count(score) as score
  from ( select id, score, row_number() over (order by score) as score_rank
           from gamescore
          where gameno = 1
                )
 where score_rank <> 1
 group by id

ROW_NUMBER()

  

在order_by_clause中指定的有序行序列中,以1开头,为应用它的每一行(分区中的每一行或查询返回的每一行)分配一个唯一的编号。

由于ORDER BY子句按升序在SCORE上,因此将删除其中一个最低分数。除非您向ORDER BY添加其他违规条件,否则这将是一个随机值。

答案 1 :(得分:1)

你可以通过几种方式实现这一目标,包括@Ben所展示的内容。从一个主要的SQL Server背景我很好奇,如果只使用ROWNUM并发现ROWNUM vs ROW_NUMBER有趣的这篇文章。我不确定它是否过时了。

全部在SQLFiddle

注意:我使用子查询因子/ CTE,因为我认为读取比内联子查询更清楚。

使用ROWNUM:

WITH OrderedScore AS (
   SELECT id, game_no, score
         ,rownum as score_rank
     FROM GameScore
    WHERE game_no = 1
    ORDER BY Score ASC   
)    
SELECT id
      ,sum(score)/count(score)
  FROM OrderedScore
 WHERE score_rank > 1
 GROUP BY id;

像Ben一样使用ROW_NUMBER()OVER(ORDER BY ...):

WITH OrderedScore AS (
   SELECT id, game_no, score
         ,ROW_NUMBER() OVER(ORDER BY score ASC) as score_rank
     FROM GameScore
    WHERE game_no = 1
    ORDER BY Score ASC   
)
SELECT id
      ,sum(score)/count(score)
  FROM OrderedScore   
 WHERE score_rank > 1
 GROUP BY id;

使用ROW_NUMBER()OVER(PARTION BY ... ORDER BY ...)如果你想在某个时候删除game_no或id的低分,我认为这会带来更大的灵活性:

WITH OrderedScore AS (
   SELECT id, game_no, score
         ,ROW_NUMBER() OVER(PARTITION BY id ORDER BY score ASC) as score_rank
     FROM GameScore
    WHERE game_no = 1
    ORDER BY Score ASC   
)  
SELECT id
      ,sum(score)/count(score)
  FROM OrderedScore   
 WHERE score_rank > 1
 GROUP BY id;