How to select ranges in a range of record in oracle

寵の児 提交于 2019-12-04 19:06:50

This is a nice way, fancy name "Tabibitosan method" given by Aketi Jyuuzou.

SQL> WITH data AS
  2    (SELECT num - DENSE_RANK() OVER(PARTITION BY status ORDER BY num) grp,
  3      status,
  4      num
  5    FROM t
  6    )
  7  SELECT MIN(num)
  8    ||' - '
  9    || MAX(num) range,
 10    COUNT(*) cnt
 11  FROM data
 12  WHERE status='A'
 13  GROUP BY grp
 14  ORDER BY grp
 15  /

RANGE         CNT
------ ----------
1 - 3           3
6 - 6           1
9 - 10          2

SQL>

Note It is better to use DENSE_RANK to avoid duplicates.

Table

SQL> SELECT * FROM t ORDER BY num;

       NUM S
---------- -
         1 A
         1 A
         2 A
         2 A
         3 A
         4 U
         5 U
         6 A
         7 U
         8 U
         9 A

       NUM S
---------- -
        10 A

12 rows selected.

There are duplicates for num = 1.

Using DENSE_RANK:

SQL> WITH data AS
  2    (SELECT num - DENSE_RANK() OVER(PARTITION BY status ORDER BY num) grp,
  3      status,
  4      num
  5    FROM t
  6    )
  7  SELECT MIN(num)
  8    ||' - '
  9    || MAX(num) range,
 10    COUNT(*) cnt
 11  FROM data
 12  WHERE status='A'
 13  GROUP BY grp
 14  ORDER BY grp
 15  /

RANGE         CNT
------ ----------
1 - 3           5
6 - 6           1
9 - 10          2

SQL>

Using ROW_NUMBER:

SQL> WITH DATA AS
  2    (SELECT num - ROW_NUMBER() OVER(PARTITION BY status ORDER BY num) grp,
  3      status,
  4      num
  5    FROM t
  6    )
  7  SELECT MIN(num)
  8    ||' - '
  9    || MAX(num) range,
 10    COUNT(*) cnt
 11  FROM data
 12  WHERE status='A'
 13  GROUP BY grp
 14  ORDER BY grp
 15  /

RANGE         CNT
------ ----------
2 - 3           2
1 - 2           2
1 - 6           2
9 - 10          2

SQL>

So, in case of duplicates, the ROW_NUMBER query would give incorrect results. You should use DENSE_RANK.

SQL Fiddle

Oracle 11g R2 Schema Setup:

create table x(
  num_ number,
  status_ varchar2(1)
  );

insert into x values(1,'A');
insert into x values(2,'A');
insert into x values(3,'A');
insert into x values(4,'U');
insert into x values(5,'U');
insert into x values(6,'A');
insert into x values(7,'U');
insert into x values(8,'U');
insert into x values(9,'A');
insert into x values(10,'A');

Query 1:

select min(num_) || '-'  || max(num_) range_, status_,
count(1) count_
from
(
  select num_, status_,
  num_ - row_number() over (order by status_, num_) y --gives a group number to each groups, which have same status over consecutive records.
  from x
 )
 where status_ = 'A'
 group by y, status_
 order by range_

Results:

| RANGE_ | STATUS_ | COUNT_ |
|--------|---------|--------|
|    1-3 |       A |      3 |
|    6-6 |       A |      1 |
|   9-10 |       A |      2 |
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!