2015-05-21 2 views
1

Если у меня есть таблица вроде этогоКак выбрать диапазоны в диапазоне записи в оракула

Number Status 
------ ------ 
1  A 
2  A 
3  A 
4  U 
5  U 
6  A 
7  U 
8  U 
9  A 
10  A 

Что запрос я могу использовать, чтобы сгруппировать диапазон в диапазоне, где состояние = A?

Range Count Status 
----- ----- ------ 
1-3 3  A 
6-6 1  A 
9-10 2  A 

Мой запрос

select min(number) || '--' || max(number), count(*), Status 
from table 
where Status = 'A' 
group by Status 

Range Count Status 
----- ----- ------ 
1-10 6  A 
+0

Можете ли вы показать нам желаемый результат? – jarlh

+0

Привет, сэр, пожалуйста, см. Блок 2 для ожидаемого результата Состояние диапазона отсчетов ----- ------ ------ 1-3 3 A 6-6 1 A 9-10 2 A –

ответ

0

Это хороший способ, причудливое название "Tabibitosan method" дается Акети 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> 

Примечание Лучше использовать DENSE_RANK, чтобы избежать дубликатов.

Таблица

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. 

Есть дубликаты для Num = 1.

Использование 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> 

Использование 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> 

Таким образом, в случае дубликатов запрос ROW_NUMBER дал бы неправильные результаты. Вы должны использовать DENSE_RANK.

+0

Как было проверено с помощью DENSE_RANK, у меня было меньше времени на выполнение. :) Спасибо. –

0

SQL Fiddle

Oracle 11g R2 Настройка схемы:

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'); 

Запрос 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 | 
+0

работает как шарм !!!! Огромное спасибо!!! : D –