Oracle SQL:至少选择前n行,继续,直到列值与最后一列不同

dua*_*ual 2 sql oracle rownum

给定以下结构的表foo(Oracle 11g):

ID | GROUP_ID
 1 | 100
 2 | 100
 3 | 100
 4 | 200
 5 | 300
 6 | 300
 7 | 400
Run Code Online (Sandbox Code Playgroud)

我想选择前n行(按ID排序)或更多,以便我总是得到一个完整的组.

例:

n = 2:我想至少获得前两行,但由于ID 3也属于组100,我也希望得到它.

n = 4:给我前四排,我很高兴;-)

n = 5:请求第1-6行.

非常感谢您的帮助!

Sha*_*nce 7

解决方案rank():

select id, group_id
from (select t.*, rank() over (order by group_id) as rnk
    from t)
where rnk <= :n;
Run Code Online (Sandbox Code Playgroud)

构建测试数据:

SQL> create table t (id number not null primary key
  2      , group_id number not null);

Table created.

SQL> insert into t values (1, 100);

1 row created.

SQL> insert into t values (2, 100);

1 row created.

SQL> insert into t values (3, 100);

1 row created.

SQL> insert into t values (4, 200);

1 row created.

SQL> insert into t values (5, 300);

1 row created.

SQL> insert into t values (6, 300);

1 row created.

SQL> insert into t values (7, 400);

1 row created.

SQL> commit;

Commit complete.
SQL>
Run Code Online (Sandbox Code Playgroud)

正在运行...

SQL> var n number
SQL> exec :n := 2;

PL/SQL procedure successfully completed.

SQL> select id, group_id
  2  from (select t.*, rank() over (order by group_id) as rnk
  3      from t)
  4  where rnk <= :n;

        ID   GROUP_ID
---------- ----------
         1        100
         2        100
         3        100

SQL> exec :n := 4;

PL/SQL procedure successfully completed.

SQL> select id, group_id
  2  from (select t.*, rank() over (order by group_id) as rnk
  3      from t)
  4  where rnk <= :n;

        ID   GROUP_ID
---------- ----------
         1        100
         2        100
         3        100
         4        200

SQL> exec :n := 5;

PL/SQL procedure successfully completed.

SQL> select id, group_id
  2  from (select t.*, rank() over (order by group_id) as rnk
  3      from t)
  4  where rnk <= :n;

        ID   GROUP_ID
---------- ----------
         1        100
         2        100
         3        100
         4        200
         5        300
         6        300

6 rows selected.
Run Code Online (Sandbox Code Playgroud)

编辑这是包含for update子句(:n = 2)的版本:

SQL> select id, group_id
  2  from T
  3  where rowid in (select RID
  4      from (select t.rowid as RID, t.*, rank() over (order by group_id) as rnk
  5          from t)
  6      where rnk <= :n)
  7  for update;

        ID   GROUP_ID
---------- ----------
         1        100
         2        100
         3        100
Run Code Online (Sandbox Code Playgroud)