繁体   English   中英

T-SQL 选择满足聚合条件的所有范围组合

[英]T-SQL Select all combinations of ranges that meet aggregate criteria

根据评论重述问题

假设我们有以下整数 ID 和计数...

id   count
1    0
2    10
3    0
4    0
5    0
6    1
7    9
8    0

我们还有一个变量@id_range int

给定@id_range的值,我们如何不使用 while 循环或游标的情况下选择满足以下条件的所有 id范围组合?

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 )。

此解决方案并未列出所有可能的组合,而只是尝试将其分组为尽可能小的行数。

希望它能涵盖所有可能的场景

-- 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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM