获取group by子句中的第n个最低值

时间:2018-09-06 21:55:38

标签: sql oracle

这很困难:我将数据以这种形式返回到临时表foo中:

id   n    v
--   -    -
1    3    1
1    3    10
1    3    100
1    3    201
1    3    300
2    1    13
2    1    21
2    1    300
4    2    1
4    2    7
4    2    19
4    2    21
4    2    300
8    1    11

id分组,我需要基于v中的值获取n的第n个最低值的行。例如,对于ID为1的组,我需要获取v等于100的行,因为100是v的第三低值。

最终结果如下所示:

id   n    v
--   -    -
1    3    100
2    1    13
4    2    7
8    1    11

有关数据的一些注释:

  • 每个ID的行数可能有所不同
  • n对于具有给定ID的每一行将始终相同
  • 给定ID的
  • n永远不会大于具有该ID的行数
  • 数据将先按id,然后按v
  • 排序

如果您可以使用通用SQL而不是特定于oracle的东西来完成奖励,那不是必须的(我怀疑rownum可能在任何解决方案中都占主导地位)。这是我的尝试,但是在得到可行的解决方案之前,我最终使自己感到困惑。

3 个答案:

答案 0 :(得分:2)

使用窗口功能

select * from
(
select t.*, row_number() over(partition by id ,n order by v) as rn
from foo  t
 ) t1 
 where t1.rn=t1.n

因为ops样本输出只需要第三高的值,所以我把条件t1.rn = 3放在哪里,尽管根据描述它应该是t1.rn = t1.n

https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=65abf8d4101d2d1802c1a05ed82c9064

答案 1 :(得分:2)

我将使用row_number函数将行号与n中的CTE列值进行比较,再进行一次CTE以按v进行行号排序描述

获取rn = 1,它是n数字组中的平均最大值。

CREATE TABLE foo(
   id int,
   n int,
   v int
);


insert into foo values (1,3,1);
insert into foo values (1,3,10);
insert into foo values (1,3,100);
insert into foo values (1,3,201);
insert into foo values (1,3,300);
insert into foo values (2,1,13);
insert into foo values (2,1,21);
insert into foo values (2,1,300);
insert into foo values (4,2,1);
insert into foo values (4,2,7);
insert into foo values (4,2,19);
insert into foo values (4,2,21);
insert into foo values (4,2,300);
insert into foo values (8,1,11);

查询1

with cte as(
    select id,n,v 
    from
    (
        select t.*, row_number() over(partition by id ,n order by n) as rn
        from foo t
    ) t1 
    where rn <= n
), maxcte as (
    select id,n,v, row_number() over(partition by id ,n order by v desc) rn 
    from cte 
)
select id,n,v 
from maxcte
where rn = 1

Results

| ID | N |   V |
|----|---|-----|
|  1 | 3 | 100 |
|  2 | 1 |  13 |
|  4 | 2 |   7 |
|  8 | 1 |  11 |

答案 2 :(得分:2)

如果您的数据库版本是12.1或更高版本,那么有一个更简单的解决方案:

SELECT DISTINCT ID, n, NTH_VALUE(v,n) OVER (PARTITION BY ID) AS v
FROM foo
ORDER BY ID;


| ID | N |   V |
|----|---|-----|
|  1 | 3 | 100 |
|  2 | 1 |  13 |
|  4 | 2 |   7 |
|  8 | 1 |  11 |

根据实际数据,您可能必须添加ORDER BY n子句和/或windowing_clause作为RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING,请参见NTH_VALUE