问题
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