Home » SQL & PL/SQL » SQL & PL/SQL » Getting boundaries (11.2.0.3)
Getting boundaries [message #632625] |
Tue, 03 February 2015 13:33 |
Amine
Messages: 375 Registered: March 2010
|
Senior Member |
|
|
Hi all;
drop table grp_tab;
create table grp_tab as
with a as
(
select 'a' my_char from dual union all
select 'b' my_char from dual union all
select 'c' my_char from dual union all
select 'd' my_char from dual union all
select 'e' my_char from dual union all
select 'f' my_char from dual
), b as
(
select 1 my_num from dual union all
select 2 my_num from dual union all
select 3 my_num from dual union all
select 4 my_num from dual union all
select 5 my_num from dual union all
select 6 my_num from dual
), a_cross_b as
(
select my_char, my_num
from a, b
), grp_tab as
(
select my_char
, my_num
, ntile(5) over (order by my_char, my_num) grp
from a_cross_b
)
select * from grp_tab
;
SQL> select * from grp_tab where grp = 1;
M MY_NUM GRP
- ---------- ----------
a 1 1
a 2 1
a 3 1
a 4 1
a 5 1
a 6 1
b 1 1
b 2 1
8 rows selected.
As we see, the first pair is (a,1) and the last one is (b,2).
I want to get each group boundaries (first and last pairs).
But when using first and last analytic functions I get this :
select
grp
, first_value(my_char) over (partition by grp order by my_char, my_num) first_char
, first_value(my_num) over (partition by grp order by my_char, my_num) first_num
, last_value(my_char) over (partition by grp order by my_char, my_num) last_char
, last_value(my_num) over (partition by grp order by my_char, my_num) last_num
from grp_tab
where grp = 1
/
GRP F FIRST_NUM L LAST_NUM
---------- - ---------- - ----------
1 a 1 a 1
1 a 1 a 2
1 a 1 a 3
1 a 1 a 4
1 a 1 a 5
1 a 1 a 6
1 a 1 b 1
1 a 1 b 2
8 rows selected.
I want to get this :
GRP F FIRST_NUM L LAST_NUM
---------- - ---------- - ----------
1 a 1 b 2
Thanks in advance,
Amine
|
|
|
|
|
|
|
|
Re: Getting boundaries [message #632632 is a reply to message #632630] |
Tue, 03 February 2015 14:18 |
Solomon Yakobson
Messages: 3273 Registered: January 2010 Location: Connecticut, USA
|
Senior Member |
|
|
Amine wrote on Tue, 03 February 2015 15:07So, we have to identify pairs before : through row_number over (partition by grp order by my_char, my_num) ?
No, use aggregate LAST/FIRST.
SY.
|
|
|
|
|
Re: Getting boundaries [message #632635 is a reply to message #632634] |
Tue, 03 February 2015 14:46 |
Amine
Messages: 375 Registered: March 2010
|
Senior Member |
|
|
with v as
(
select
grp
, my_char
, my_num
, first_value(my_char) over (partition by grp order by my_char, my_num) first_char
, first_value(my_num) over (partition by grp order by my_char, my_num) first_num
from grp_tab
--where grp = 1
)
select
v.*
, last_value(my_char) over (partition by grp, first_char, first_num order by my_char, my_num) last_char
, last_value(my_num) over (partition by grp, first_char, first_num order by my_char, my_num) last_num
from v
order by grp
;
|
|
|
|
|
Re: Getting boundaries [message #632640 is a reply to message #632638] |
Tue, 03 February 2015 15:03 |
Solomon Yakobson
Messages: 3273 Registered: January 2010 Location: Connecticut, USA
|
Senior Member |
|
|
For those who can't RTFM:
FIRST and LAST are very similar functions. Both are aggregate and analytic functions that operate on a set of values from a set of rows that rank as the FIRST or LAST with respect to a given sorting specification. If only one row ranks as FIRST or LAST, then the aggregate operates on the set with only one element.
SY.
|
|
|
|
|
|
|
|
Re: Getting boundaries [message #632893 is a reply to message #632648] |
Fri, 06 February 2015 11:47 |
Amine
Messages: 375 Registered: March 2010
|
Senior Member |
|
|
SQL> with a as
2 (
3 select 'a' my_char from dual union all
4 select 'b' my_char from dual union all
5 select 'c' my_char from dual union all
6 select 'd' my_char from dual union all
7 select 'e' my_char from dual union all
8 select 'f' my_char from dual
9 ), b as
10 (
11 select 1 my_num from dual union all
12 select 2 my_num from dual union all
13 select 3 my_num from dual union all
14 select 4 my_num from dual union all
15 select 5 my_num from dual union all
16 select 6 my_num from dual
17 ), a_cross_b as
18 (
19 select my_char, my_num
20 from a, b
21 ), grp_tab as
22 (
23 select
24 my_char
25 , my_num
26 , ntile(5) over (order by my_char, my_num) grp
27 from a_cross_b
28 ), grp_tab_with_rn as
29 (
30 select grp_tab.*, row_number() over (partition by grp order by my_char, m
y_num) rn from grp_tab
31 ), boundaries as
32 (
33 select
34 grp
35 , min(rn) min_rn
36 , max(rn) max_rn
37 from grp_tab_with_rn
38 group by grp
39 )
40 select boundaries.grp
41 , min.my_char
42 , min.my_num
43 , max.my_char
44 , max.my_num
45 from boundaries, grp_tab_with_rn min, grp_tab_with_rn max
46 where 1 = 1
47 and boundaries.grp = max.grp
48 and boundaries.grp = min.grp
49 and boundaries.min_rn = min.rn
50 and boundaries.max_rn = max.rn
51 ;
GRP M MY_NUM M MY_NUM
---------- - ---------- - ----------
1 a 1 b 2
2 b 3 c 3
3 c 4 d 4
4 d 5 e 5
5 e 6 f 6
SQL>
To Michel and SY, how to do it with FIRST and LAST ?
|
|
|
Re: Getting boundaries [message #632894 is a reply to message #632893] |
Fri, 06 February 2015 11:58 |
|
Michel Cadot
Messages: 68645 Registered: March 2007 Location: Nanterre, France, http://...
|
Senior Member Account Moderator |
|
|
Here are 3 ways to do it with a single pass in the table: FIRST/LAST and ROW_NUMBER mentioned by Solomon and old MIN/MAX I told you:
SQL> col first_char format a10
SQL> col last_char format a10
SQL> select grp,
2 min(my_char) keep (dense_rank first order by my_char, my_num) first_char,
3 min(my_num) keep (dense_rank first order by my_char, my_num) first_num,
4 max(my_char) keep (dense_rank last order by my_char, my_num) last_char,
5 max(my_num) keep (dense_rank last order by my_char, my_num) last_num
6 from grp_tab
7 group by grp
8 order by grp
9 /
GRP FIRST_CHAR FIRST_NUM LAST_CHAR LAST_NUM
---------- ---------- ---------- ---------- ----------
1 a 1 b 2
2 b 3 c 3
3 c 4 d 4
4 d 5 e 5
5 e 6 f 6
5 rows selected.
SQL> select grp,
2 min(decode(rn1, 1, my_char)) first_char,
3 min(decode(rn1, 1, my_num)) first_num,
4 max(decode(rn2, 1, my_char)) last_char,
5 max(decode(rn2, 1, my_num)) last_num
6 from (select grp, my_char, my_num,
7 row_number() over (partition by grp order by my_char, my_num) rn1,
8 row_number() over (partition by grp order by my_char desc, my_num desc) rn2
9 from grp_tab)
10 where rn1 = 1 or rn2 = 1
11 group by grp
12 order by grp
13 /
GRP FIRST_CHAR FIRST_NUM LAST_CHAR LAST_NUM
---------- ---------- ---------- ---------- ----------
1 a 1 b 2
2 b 3 c 3
3 c 4 d 4
4 d 5 e 5
5 e 6 f 6
5 rows selected.
SQL> select grp,
2 substr(mini,1,instr(mini,'/')-1) first_char,
3 to_number(substr(mini,instr(mini,'/')+1)) first_num,
4 substr(maxi,1,instr(mini,'/')-1) last_char,
5 to_number(substr(maxi,instr(mini,'/')+1)) last_num
6 from (select grp,
7 min(my_char||'/'||to_char(my_num)) mini,
8 max(my_char||'/'||to_char(my_num)) maxi
9 from grp_tab
10 group by grp)
11 order by grp
12 /
GRP FIRST_CHAR FIRST_NUM LAST_CHAR LAST_NUM
---------- ---------- ---------- ---------- ----------
1 a 1 b 2
2 b 3 c 3
3 c 4 d 4
4 d 5 e 5
5 e 6 f 6
5 rows selected.
|
|
|
|
Goto Forum:
Current Time: Fri Apr 26 00:23:10 CDT 2024
|