-- take the data below for example, we can see that records from 2 to 3 is 0, and records from 8 to 10 is also 0, -- and we want to answer this question using SQL declare @t table(seqno int identity, val int) insert @t(val) select 5 insert @t(val) select 0 insert @t(val) select 0 insert @t(val) select 1 insert @t(val) select 1 insert @t(val) select 2 insert @t(val) select 2 insert @t(val) select 0 insert @t(val) select 0 insert @t(val) select 0 /* pass 1: analysis the raw data select 'a.seqno'=a.seqno, 'a.val'=a.val ,'b.seqno'=b.seqno, 'b.val'=b.val from @t a cross join @t b where a.val = 0 -- pass 1 output a.seqno a.val b.seqno b.val ----------- ----------- ----------- ----------- 2 0 1 5 2 0 2 0 2 0 3 0 2 0 4 1 2 0 5 1 2 0 6 2 2 0 7 2 2 0 8 0 2 0 9 0 2 0 10 0 3 0 1 5 3 0 2 0 3 0 3 0 3 0 4 1 3 0 5 1 3 0 6 2 3 0 7 2 3 0 8 0 3 0 9 0 3 0 10 0 8 0 1 5 8 0 2 0 8 0 3 0 8 0 4 1 8 0 5 1 8 0 6 2 8 0 7 2 8 0 8 0 8 0 9 0 8 0 10 0 9 0 1 5 9 0 2 0 9 0 3 0 9 0 4 1 9 0 5 1 9 0 6 2 9 0 7 2 9 0 8 0 9 0 9 0 9 0 10 0 10 0 1 5 10 0 2 0 10 0 3 0 10 0 4 1 10 0 5 1 10 0 6 2 10 0 7 2 10 0 8 0 10 0 9 0 10 0 10 0 */ /* pass 2: calc start and end of a range, base on data retrieve on pass 1, let's find out how the compute the start of the range CASE 1: a.seqno a.val b.seqno b.val ----------- ----------- ----------- ----------- 2 0 1 5 2 0 2 0 -- target 2 0 3 0 2 0 4 1 2 0 5 1 2 0 6 2 2 0 7 2 2 0 8 0 2 0 9 0 2 0 10 0 for a.seqno=2, calc range_start: for all b.seqno < a.seqno and b.val <> 0 (b.seqno=1,b.val=5), select the max(b.seqno) (in this case, value = 1) + 1, so range_start = 2 CASE 2: a.seqno a.val b.seqno b.val ----------- ----------- ----------- ----------- 9 0 1 5 9 0 2 0 9 0 3 0 9 0 4 1 9 0 5 1 9 0 6 2 9 0 7 2 9 0 8 0 -- target 9 0 9 0 9 0 10 0 for a.seqno=9, calc range_start: for all b.seqno < a.seqno and b.val <> 0 (b.seqno=1,b.val=5), (b.seqno=4,b.val=1), (b.seqno=5,b.val=1), (b.seqno=6,b.val=2), (b.seqno=7,b.val=2), select the max(b.seqno) (in this case, value = 7) + 1, so range_start = 8 */ select a.seqno, a.val ,range_start=max(case when b.seqno < a.seqno and b.val <> 0 then b.seqno else null end)+1 ,range_end=min(case when b.seqno > a.seqno and b.val <> 0 then b.seqno else null end)-1 from @t a cross join @t b where a.val = 0 group by a.seqno, a.val /* pass 2 output seqno val range_start range_end ----------- ----------- ----------- ----------- 2 0 2 3 3 0 2 3 8 0 8 NULL 9 0 8 NULL 10 0 8 NULL */ /* pass 3: in pass 2, if first/last record is 0, then the range_start/range_end will be examined to the value NULL, so let's fix this bug. */ select a.seqno, a.val ,range_start=isnull(max(case when b.seqno < a.seqno and b.val <> 0 then b.seqno else null end)+1, min(b.seqno)) ,range_end=isnull(min(case when b.seqno > a.seqno and b.val <> 0 then b.seqno else null end)-1, max(b.seqno)) from @t a cross join @t b where a.val = 0 group by a.seqno, a.val /* pass 3 output seqno val range_start range_end ----------- ----------- ----------- ----------- 2 0 2 3 3 0 2 3 8 0 8 10 9 0 8 10 10 0 8 10 */