说我们有以下整数id和计数...
id count
1 0
2 10
3 0
4 0
5 0
6 1
7 9
8 0
我们还有一个变量@id_range int
。
给定@id_range
的值,我们如何才能选择id ranges 的所有组合,而又不使用满足条件的while循环或游标以下标准?
1)组合中不能有两个范围重叠(每个范围的最小值和最大值均包括在内)
2)sum(count)
(范围组合必须等于初始数据集的sum(count)
(在这种情况下为20)
3)仅包含sum(count)
> 0 的范围
最简单的情况是当@id_range = max(id) - min(id)
或7给出上述数据时。在这种情况下,只有一种解决方案:
minId maxId count
---------------------
1 8 20
但是如果以@id_range = 1
为例,将有4种可能的解决方案:
解决方案1:
minId maxId count
---------------------
1 2 10
5 6 1
7 8 9
解决方案2:
minId maxId count
---------------------
1 2 10
6 7 10
解决方案3:
minId maxId count
---------------------
2 3 10
5 6 1
7 8 9
解决方案4:
minId maxId count
---------------------
2 3 10
6 7 10
最终目标是确定范围最小的解决方案(解决方案2和4,在上面的示例中,@id_range = 1
)。
答案 0 :(得分:0)
此解决方案未列出所有可能的组合,而只是尝试将其组合到尽可能少的行中。
希望它将涵盖所有可能的情况
-- create the sample table
declare @sample table
(
id int,
[count] int
)
-- insert some sample data
insert into @sample select 1, 0
insert into @sample select 2, 10
insert into @sample select 3, 0
insert into @sample select 4, 0
insert into @sample select 5, 0
insert into @sample select 6, 1
insert into @sample select 7, 9
insert into @sample select 8, 0
-- the @id_range
declare @id_range int = 1
-- the query
; with
cte as
(
-- this cte identified those rows with count > 0 and group them together
-- sign(0) gives 0, sign(+value) gives 1
-- basically it is same as case when [count] > 0 then 1 else 0 end
select *,
grp = row_number() over (order by id)
- dense_rank() over(order by sign([count]), id)
from @sample
),
cte2 as
(
-- for each grp in cte, assign a sub group (grp2). each sub group
-- contains @id_range number of rows
select *,
grp2 = (row_number() over (partition by grp order by id) - 1)
/ (@id_range + 1)
from cte
where count > 0
)
select MinId = min(id),
MaxId = min(id) + @id_range,
[count] = sum(count)
from cte2
group by grp, grp2