Skip to Main Content

Breadcrumb

Question and Answer

Chris Saxon

Thanks for the question, Susana.

Asked: August 04, 2016 - 9:46 am UTC

Last updated: August 04, 2016 - 3:08 pm UTC

Version: 10.1.2

Viewed 1000+ times

You Asked

Hi team,

I have a table with intervals of numbers. However, my table have intervals that overlap and a number can be in more than one interval.
For example,

start_interval | end_interval
1 | 2
2 | 4
3 | 6
...

The number 2 can be in both intervals (1-2) and (2-4). The number 3 can also be in two intervals (2-4) and (3-6), and so on.
I need a query to identify the overlapped intervals.
For example:

Interval || Overlapped interval
start_interval | end_interval || start_interval | end_interval
1 | 2 || 2 | 4
2 | 4 || 3 | 6
...

Below you can find my query:

with t1 (start_int, end_int) as (select 1 start_int, 2 end_int from dual
                                 union all
                                 select start_int+1 start_int, end_int+2 end_int from t1 where start_int < 20),
     t2 as (select t1.start_int start_int_1, t1.end_int end_int_1, tt.start_int start_int_2, tt.end_int end_int_2
              from t1
             cross join t1 tt
             where t1.start_int <> tt.start_int
               and t1.end_int <> tt.end_int
               and (tt.start_int <= t1.end_int and tt.end_int >= t1.start_int))
select t2.start_int_1, t2.end_int_1,
       t2.start_int_2, t2.end_int_2
  from t2
order by 1,2,3,4


However, my query returns repeated groups. For example:

Interval || Overlapped interval
start_interval | end_interval || start_interval | end_interval
1 | 2 || 2 | 4
2 | 4 || 1 | 2

2 | 4 || 3 | 6
3 | 6 || 2 | 4
...

I understand why I am getting duplicated groups, but I don't know how to remove them.
Can you please help me?

Thanks.

and Chris said...

To exclude those you've already considered, check that the start_int of one table is strictly less than that in the other:

with t1 (start_int, end_int) as (
  select 1 start_int, 2 end_int from dual
  union all
  select start_int+1 start_int, end_int+2 end_int 
 from t1 where start_int < 4
), t2 as (
  select t1.start_int start_int_1, t1.end_int end_int_1, tt.start_int  start_int_2, tt.end_int end_int_2
 from t1
  cross join t1 tt
  where t1.start_int <> tt.start_int
   and t1.end_int <> tt.end_int
   and (tt.start_int <= t1.end_int and tt.end_int >= t1.start_int)
   and  t1.start_int < tt.start_int
)
select t2.start_int_1, t2.end_int_1,
       t2.start_int_2, t2.end_int_2
  from t2
order by 1,2,3,4;

START_INT_1  END_INT_1  START_INT_2  END_INT_2  
1            2          2            4          
2            4          3            6          
2            4          4            8          
3            6          4            8

Rating

  (1 rating)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Susana Oliveira, August 04, 2016 - 4:52 pm UTC

Great! That was exactly what I was looking for. Thanks.