如何select ranges in a range of record in oracle
How to select ranges in a range of record in oracle
如果我有这样的table
Number Status
------ ------
1 A
2 A
3 A
4 U
5 U
6 A
7 U
8 U
9 A
10 A
我可以使用什么查询将范围分组为 Status = 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
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_
| RANGE_ | STATUS_ | COUNT_ |
|--------|---------|--------|
| 1-3 | A | 3 |
| 6-6 | A | 1 |
| 9-10 | A | 2 |
这是一个很好的方法,由 Aketi Jyuuzou 起的别致的名字“Tabibitosan method”。
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
避免重复
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.
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.
如果我有这样的table
Number Status
------ ------
1 A
2 A
3 A
4 U
5 U
6 A
7 U
8 U
9 A
10 A
我可以使用什么查询将范围分组为 Status = 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
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_
| RANGE_ | STATUS_ | COUNT_ |
|--------|---------|--------|
| 1-3 | A | 3 |
| 6-6 | A | 1 |
| 9-10 | A | 2 |
这是一个很好的方法,由 Aketi Jyuuzou 起的别致的名字“Tabibitosan method”。
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
避免重复
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.
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.