oracle sql选择最大前x行

时间:2017-11-02 11:49:07

标签: sql oracle

这是我的表结构:

ID   points
-----------
1        20
2        30
3        20
4        30
5        20

我要奖励得分最高的前三名。如果多个人拥有相同数量的积分,则无论是获得奖励还是没有奖励。

选择应该是什么样的?我试图使用ROW_NUMBER()

select * from (
    select id, row_number() over (order by points desc) as rn from test3
) tab where rn <= 3;

返回3行 - 它打破了上面发布的条件。在这种情况下它应该只返回2行(因为有太多的20个值)。我也试过使用RANK(),但它也错了,因为它会返回所有行。

3 个答案:

答案 0 :(得分:3)

row_number()使用累计count()外,如果数量超过三个,则不予奖励:

with test3(id, points) as (
    select 1, 20 from dual union all
    select 2, 30 from dual union all
    select 3, 20 from dual union all
    select 4, 30 from dual union all
    select 5, 20 from dual )
select * 
  from (select t.*, row_number() over (order by points desc) rnk, 
               count(1) over (order by points desc) cnt
          from test3 t)
  where rnk <= 3 and cnt <= 3

答案 1 :(得分:1)

使用dense_rank()rank()

select *
from (select id, dense_rank() over (order by points desc) as rn
      from test3
     ) tab
where rn <= 3;

如果您希望拥有三个不同分数最高的人,请使用dense_rank()。这可能就是你想要的。

请注意,如果分数为

10, 10, 10, 10, 9, 8

然后将选出所有人。如果你想要至少三个但没有额外的东西,那么查询有点棘手:

select t3.*
from test3 t3
where t3.score >= (select max(tt3.point)
                   from (select t3.*, row_number() over (order by points desc) as seqnum
                         from test3 t3
                         order by points desc
                        ) tt3
                   where seqnum <= 3
                  );

在Oracle 12C中,这可以简化为:

select t3.*
from test3 t3
where t3.score >= (select tt3.point
                   from test3 tt3
                   order by points desc
                   offset 2 fetch first 1 row only
                  );

答案 2 :(得分:0)

    select * from (
        select id, RANK() over (Partition By Points order by ID) as rn from 
    test3) tab where rn <= 3;