7

I need to query a table, containing a step id + value. The result will list the intervals, along with their associated value. Intervals here are defined as "succession of contiguous ids of steps, sharing same data value".

I'm having a hard time describing it in words, so please see this:

From this table

  Step ! Data
  ------------
   1   !  A
   2   !  A
   3   !  A
   5   !  A
   6   !  B
  10   !  A

I need the following report

  From ! To   ! Data
  -------------------
     1 !   3  !   A
     5 !   5  !   A
     6 ! null !   B
    10 ! null !   A

I thought lead() would help me out here, but did not succeed.

Thomas
  • 4,827
  • 5
  • 28
  • 60
  • 2
    It seems the data is considered separately for values A and B? Then: Why is the result (5, 5) for that row, but then (6, NULL) and not (6, 6)? – mathguy Dec 20 '16 at 12:58
  • Oh... so, for the LAST occurrence of each "Data" value, the interval should be open-ended, but all other intervals are "close-ended"? – mathguy Dec 20 '16 at 13:05
  • You got it right, still this is kinda over-specified: "To" values showing identical as "From" instead of NULL is perfectly acceptable – user2999190 Dec 20 '16 at 13:13
  • 1
    If we would also have `A ! 11` would you like the last range to be '10 ! null` or `10 ! 11'? – David דודו Markovitz Dec 20 '16 at 13:42

2 Answers2

1

You can do this by generating a sequence of numbers and subtracting from the step. This will be a constant when the values are sequential:

select min(step) as from_step, max(step) as to_step, data
from (select t.*,
            row_number() over (partition by data order by step) as seqnum
     from t
    ) t
group by (step - seqnum), data;

EDIT:

It is not quite clear where the NULLs are coming from. If I speculate that they are the last values for each value, you can do:

select min(step) as from_step,
       (case when max(step) <> max_step then max(step) end) as to_step,
       data
from (select t.*,
             max(step) over (partition by data) as max_step
             row_number() over (partition by data order by step) as seqnum
     from t
    ) t
group by (step - seqnum), data, max_step;
Gordon Linoff
  • 1,122,135
  • 50
  • 484
  • 624
1
select      min (step)                                                   as "from"
           ,nullif (max (step),max(min(step)) over (partition by data))  as "to"
           ,data

from       (select      step,data
                       ,row_number () over (partition by data order by step) as n

            from        t
            ) 

group by    data
           ,step - n            

order by    "from"           
David דודו Markovitz
  • 31,018
  • 5
  • 48
  • 69