您的位置:首页 > 产品设计 > UI/UE

Compute the region of specific value inside a dataset

2006-05-11 13:53 465 查看
-- 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
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐