[英]Oracle SQL: Select at least the first n rows, continue until a column value is different from the last one
給出具有以下結構的表foo(Oracle 11g):
ID | GROUP_ID
1 | 100
2 | 100
3 | 100
4 | 200
5 | 300
6 | 300
7 | 400
我想選擇前n行(按ID排序)或更多,這樣我總能得到一個完整的組。
例:
n = 2:我想至少獲得前兩行,但是由於ID 3也屬於組100,所以我也希望得到它。
n = 4:給我前四行,我很高興;-)
n = 5:請求1-6行。
非常感謝您的幫助!
使用rank()
解決方案:
select id, group_id
from (select t.*, rank() over (order by group_id) as rnk
from t)
where rnk <= :n;
建築測試數據:
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>
正在運行...
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.
編輯這是包含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
如果您的ID
始終從1開始是連續的(無間隔),並且您的Group_ID
從未在其他地方作為第二個組出現。 如果您的Group_ID
的價值始終在上升...
SELECT
*
FROM
foo
WHERE
Group_ID <= (SELECT Group_ID FROM foo WHERE ID = n)
ORDER BY
ID
您將從ID
和Group_ID
上具有單獨的索引中Group_ID
如果始終確實GROUP_ID
是連續且遞增的,那么可以使用SQL的解析ROW_NUMBER()
函數輕松解決此問題:
SQL> select id
2 , group_id
3 from foo
4 where group_id <= ( select group_id
5 from (
6 select f.group_id
7 , row_number() over (order by f.id asc) rn
8 from foo f
9 )
10 where rn = &n )
11 order by id
12 /
Enter value for n: 2
old 10: where rn = &n )
new 10: where rn = 2 )
ID GROUP_ID
---------- ----------
1 100
2 100
3 100
SQL> r
1 select id
2 , group_id
3 from foo
4 where group_id <= ( select group_id
5 from (
6 select f.group_id
7 , row_number() over (order by f.id asc) rn
8 from foo f
9 )
10 where rn = &n )
11* order by id
Enter value for n: 4
old 10: where rn = &n )
new 10: where rn = 4 )
ID GROUP_ID
---------- ----------
1 100
2 100
3 100
4 200
SQL> r
1 select id
2 , group_id
3 from foo
4 where group_id <= ( select group_id
5 from (
6 select f.group_id
7 , row_number() over (order by f.id asc) rn
8 from foo f
9 )
10 where rn = &n )
11* order by id
Enter value for n: 5
old 10: where rn = &n )
new 10: where rn = 5 )
ID GROUP_ID
---------- ----------
1 100
2 100
3 100
4 200
5 300
6 300
6 rows selected.
SQL>
如果我們假設group_id是連續的並且是遞增的,那么@Shannon的答案將非常有效。 如果我們不做這個假設,並且我們有看起來像這樣的數據,例如:
SQL> select * from foo order by id;
ID GROUP_ID
-- --------
1 100
2 100
3 100
4 200
6 100
7 400
9 500
10 500
11 500
12 600
這是一個棘手的問題。 例如,如果N = 3、4或5,則需要通過ID = 6獲取行。對於N = 6,我們需要高達ID =7。對於N = 7,我們需要通過ID = 11。
我相信無論group_id的順序如何,該查詢都有效:
對於N = 7:
WITH q AS (SELECT ID, group_id
, row_number() OVER (ORDER BY ID) rn
, MAX(id) OVER (PARTITION BY group_id) rn2
FROM foo)
SELECT ID, group_id FROM q
WHERE ID <= (SELECT max(rn2) FROM q WHERE rn <= :N)
ORDER BY ID;
ID GROUP_ID
-- --------
1 100
2 100
3 100
4 200
6 100
7 400
9 500
10 500
11 500
9 rows selected
對於N = 6:
ID GROUP_ID
-- --------
1 100
2 100
3 100
4 200
6 100
7 400
對於N = 1:
ID GROUP_ID
-- --------
1 100
2 100
3 100
4 200
6 100
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.