Home » SQL & PL/SQL » SQL & PL/SQL » Getting boundaries (11.2.0.3)
Getting boundaries [message #632625] Tue, 03 February 2015 13:33 Go to next message
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 #632626 is a reply to message #632625] Tue, 03 February 2015 13:37 Go to previous messageGo to next message
Michel Cadot
Messages: 68645
Registered: March 2007
Location: Nanterre, France, http://...
Senior Member
Account Moderator

Don't use analytic functions for this.
This is aggregate: you want the min and the max of (my_char, my_num) (the "order by" of ntime) for each group.

Re: Getting boundaries [message #632627 is a reply to message #632626] Tue, 03 February 2015 13:41 Go to previous messageGo to next message
Amine
Messages: 375
Registered: March 2010
Senior Member

Thanks Michel for the reply. Your suggestion won't work because min and max don't take in account the pairs, look :

SQL> select
  2  grp
  3  , min(my_char) first_char
  4  , min(my_num)  first_num
  5  , max(my_char) last_char
  6  , max(my_num)  last_num
  7  from grp_tab
  8  --where grp = 1
  9  --*/
 10  group by grp
 11  /

       GRP F  FIRST_NUM L   LAST_NUM
---------- - ---------- - ----------
         1 a          1 b          6
         2 b          1 c          6
         4 d          1 e          6
         5 e          1 f          6
         3 c          1 d          6

SQL>
Re: Getting boundaries [message #632628 is a reply to message #632627] Tue, 03 February 2015 13:43 Go to previous messageGo to next message
Michel Cadot
Messages: 68645
Registered: March 2007
Location: Nanterre, France, http://...
Senior Member
Account Moderator

Just think a little bit and you will do it.
How to put a pair in MIN/MAX?

Re: Getting boundaries [message #632629 is a reply to message #632627] Tue, 03 February 2015 14:06 Go to previous messageGo to next message
Solomon Yakobson
Messages: 3273
Registered: January 2010
Location: Connecticut, USA
Senior Member
Amine wrote on Tue, 03 February 2015 14:41
Thanks Michel for the reply. Your suggestion won't work because min and max don't take in account the pairs, look :


RTFM on LAST/FIRST functions.

SY.
Re: Getting boundaries [message #632630 is a reply to message #632628] Tue, 03 February 2015 14:07 Go to previous messageGo to next message
Amine
Messages: 375
Registered: March 2010
Senior Member

So, we have to identify pairs before : through row_number over (partition by grp order by my_char, my_num) ?
Re: Getting boundaries [message #632632 is a reply to message #632630] Tue, 03 February 2015 14:18 Go to previous messageGo to next message
Solomon Yakobson
Messages: 3273
Registered: January 2010
Location: Connecticut, USA
Senior Member
Amine wrote on Tue, 03 February 2015 15:07
So, 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 #632633 is a reply to message #632632] Tue, 03 February 2015 14:37 Go to previous messageGo to next message
Amine
Messages: 375
Registered: March 2010
Senior Member

Thank you for pushing me to find the solution myself, but I give up now, any tip ?
Re: Getting boundaries [message #632634 is a reply to message #632633] Tue, 03 February 2015 14:40 Go to previous messageGo to next message
Michel Cadot
Messages: 68645
Registered: March 2007
Location: Nanterre, France, http://...
Senior Member
Account Moderator

Post what you tried.
Not the first query but the one you tried with the last hints.

Re: Getting boundaries [message #632635 is a reply to message #632634] Tue, 03 February 2015 14:46 Go to previous messageGo to next message
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 #632636 is a reply to message #632635] Tue, 03 February 2015 14:56 Go to previous messageGo to next message
Michel Cadot
Messages: 68645
Registered: March 2007
Location: Nanterre, France, http://...
Senior Member
Account Moderator

You didn't read Solomon's link, did you?

Re: Getting boundaries [message #632638 is a reply to message #632636] Tue, 03 February 2015 15:01 Go to previous messageGo to next message
Amine
Messages: 375
Registered: March 2010
Senior Member

I did, but I'm confused : you said do not use analytic functions use aggregates and LAST and FIRST are analytic only not like min max
Re: Getting boundaries [message #632640 is a reply to message #632638] Tue, 03 February 2015 15:03 Go to previous messageGo to next message
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 #632641 is a reply to message #632640] Tue, 03 February 2015 15:04 Go to previous messageGo to next message
Solomon Yakobson
Messages: 3273
Registered: January 2010
Location: Connecticut, USA
Senior Member
But you can also use ROW_NUMBER without using GROUP BY.

SY.
Re: Getting boundaries [message #632643 is a reply to message #632641] Tue, 03 February 2015 15:06 Go to previous messageGo to next message
Solomon Yakobson
Messages: 3273
Registered: January 2010
Location: Connecticut, USA
Senior Member
And if you read docs on FIRST you'll see both aggregate ana analytic examples.

SY.
Re: Getting boundaries [message #632645 is a reply to message #632643] Tue, 03 February 2015 15:09 Go to previous messageGo to next message
Michel Cadot
Messages: 68645
Registered: March 2007
Location: Nanterre, France, http://...
Senior Member
Account Moderator

... and if you can't use aggregate FIRST/LAST you can use an old MIN/MAX aggregate way which existed when FIRST/LAST were not there.

Re: Getting boundaries [message #632646 is a reply to message #632643] Tue, 03 February 2015 15:11 Go to previous messageGo to next message
Amine
Messages: 375
Registered: March 2010
Senior Member

Sorry, I give up ! Had a tiring day, good night
Re: Getting boundaries [message #632648 is a reply to message #632646] Tue, 03 February 2015 15:14 Go to previous messageGo to next message
Michel Cadot
Messages: 68645
Registered: March 2007
Location: Nanterre, France, http://...
Senior Member
Account Moderator

Hint: in your case, you will know you use aggregate function if you use "GROUP BY grp".

Re: Getting boundaries [message #632893 is a reply to message #632648] Fri, 06 February 2015 11:47 Go to previous messageGo to next message
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 Go to previous messageGo to next message
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.

Re: Getting boundaries [message #632903 is a reply to message #632894] Fri, 06 February 2015 15:03 Go to previous message
Amine
Messages: 375
Registered: March 2010
Senior Member

Merci Michel !
Previous Topic: Insert data through Java class
Next Topic: ORA-06550: line 15, column 5: PLS-00103: Encountered the symbol "IF" when expecting one of the follo
Goto Forum:
  


Current Time: Fri Apr 26 00:23:10 CDT 2024