Question

Which Oracle SQL-technique is possible to use for concatenate this rows:

id | from | to
--------------
 a |   20 | 25
 a |   26 | 30
 a |   32 | 40
 b |    1 |  5
 b |    7 | 10
 b |   11 | 20

for such result:

 a |   20 | 30
 a |   32 | 40
 b |    1 |  5
 b |    7 | 20

? Assumed that from and to is start and end of an integer period, and necessary to choose an non-breaking periods for id's

Just looking for right direction and example, can this be done using group by or connect by or something else?

DB is Oracle Database 11g Enterprise Edition Release 11.1.0.6.0 - 64bit Production

Was it helpful?

Solution

Maybe something similar:

select
    field_id,
    min(field_from),
    max(field_to)
from (
    select
        field_from,
        field_to,
        field_id,
        sum(willSum) over(partition by field_id order by field_from) as GID
    from (
        select
            field_from,
            field_to,
            field_id,
            case when field_from
                    = Lag(field_to) over(partition by field_id order by field_from)
                 then 0 else 1 end as willSum + 1
        from
            rj_mytest
        )
    )
group by
    field_id,
    GID
order by
    field_id,
    min(field_from);

There are a few similar example: https://forums.oracle.com/thread/969005

OTHER TIPS

select id, max("from") as "from", max("to") as "to"
from (
  select 
    nvl(prv.id, nxt.id) id,
    nxt."from", 
    prv."to", 
    nvl2(nxt."to", 
      row_number() over (partition by nxt.id order by nxt."from"), 
      row_number() over (partition by prv.id order by prv."to")) rn
  from t prv full join t nxt on
    prv.id = nxt.id and prv."to" + 1 = nxt."from"
  where nxt."to" + prv."to" is null 
)
group by id, rn

fiddle

Another approach, which uses model clause to assign a group number to a consecutive pairs of values:

select id1
     , min(from1) as from1
     , max(to1)   as to1
  from (select *
          from t1
          model
          partition by (id1)
          dimension by (row_number() over(partition by id1 order by from1) as rn)
          measures(from1, to1, 1 as grp)
          rules(
              grp[rn] = case
                          when from1[cv()] = nvl(to1[cv()-1] + 1, from1[cv()]) 
                          then nvl(grp[cv() - 1], 1)
                          else grp[cv() - 1] + 1
                        end 
               )
)
group by id1
       , grp
order by id1
       , from1

Result:

ID1      FROM1        TO1
--- ---------- ----------
a           20         30 
a           32         40 
b            1          5 
b            7         20

SQLFiddle Demo

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top