Excluding only one MIN value on Oracle SQL

橙三吉。 提交于 2019-12-11 03:39:24

问题


I am trying to select all but the lowest value in a column (GameScore), but when there are two of this lowest value, my code excludes both (I know why it does this, I just don't know exactly how to correct it and include one of the two lowest values).

The code looks something like this:

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

So if I am drawing from 5 values, but one of the rows only pulls 3 scores because the bottom two are the same, how do I include the 4th? Thanks.


回答1:


In order to do this you have to separate them up somehow; your current issue is that the 2 lowest scores are the same so any (in)equality operation performed on either values treats the other one identically.

You could use something like the analytic query ROW_NUMBER() to uniquely identify rows:

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():

assigns a unique number to each row to which it is applied (either each row in the partition or each row returned by the query), in the ordered sequence of rows specified in the order_by_clause, beginning with 1.

As the ORDER BY clause is on SCORE in ascending order one of the lowest score will be removed. This will be a random value unless you add other tie-breaker conditions to the ORDER BY.




回答2:


You can do this a few ways, including what @Ben shows. From a mostly SQL Server background I was curious if just ROWNUM could be used and found this piece on ROWNUM vs ROW_NUMBER interesting. I'm not sure if it is dated.

All in a SQLFiddle.

Note: I'm using a subquery factoring/CTE as I think the read more clearly than in-line subqueries.

Using 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;

Using ROW_NUMBER() OVER(ORDER BY...) as Ben does:

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;

Using ROW_NUMBER() OVER(PARTION BY...ORDER BY...) which I think leads to more flexibility if you want to remove the low score by game_no or id at some point:

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;


来源:https://stackoverflow.com/questions/26442592/excluding-only-one-min-value-on-oracle-sql

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!