SQL Server:按列的总和分组

时间:2017-05-08 16:08:31

标签: sql sql-server

我需要将数据汇总到包含数字数据的一列。

我有以下数据:

ID | Amount
---+-------
1  | 44
2  | 15
3  | 16
4  | 8
5  | 16 

结果,我期待的是:

ID | Amount
---+-------
1  | 44
2  | 31
4  | 24

查询应将ID列按Amount列排序的数据按最大金额32的部分进行分组。如果金额大于32,则应将其显示为一个'组&# 39 ;.结果应包含Min(ID)SUM(Amount),当组合多个记录时,该结果不能超过32。

2 个答案:

答案 0 :(得分:0)

我知道如何实现这一目标的唯一方法是使用迭代(尽管在你的情况下,如果你有足够的单个值超过32,那么你可能能够使用更有效的方法)。

SQL Server查询中的迭代由递归CTE处理(一旦你放弃了游标):

with v as (
      select *
      from (values (1, 44), (2, 15), (3, 16), (4, 8), (5, 16) ) v(id, amount)
     ),
     t as (
      select v.*, row_number() over (order by id) as seqnum
     ),
     cte as (
      select seqnum, id, amount, id as grp
      from t
      where seqnum = 1
      union all
      select t.seqnum, t.id,
             (case when t.amount + cte.amount > 32 then t.amount else t.amount + cte.amount end) as amount,
             (case when t.amount + cte.amount > 32 then t.id else cte.grp end) as grp
      from cte join
           t
           on cte.seqnum = t.seqnum + 1
     )
select grp, max(amount)
from cte
group by grp;

我应该注意在外部查询中使用max(amount)假设值永远不会为负。稍作修改即可处理这种情况。

此外,使用t的中间结果对于您提供的数据并不是绝对必要的。它确保join中使用的列实际上没有间隙。

答案 1 :(得分:0)

您可以尝试使用最初分配的rownumbers这个版本,并在递归cte中将每一行连接到前一行。如果运行总和> 32一个新组开始。

with rownums as (select t.*,row_number() over(order by id) as rnum from t)
,cte(rnum,id,amount,runningsum,grp) as (select rnum,id,amount,amount,1  from rownums where rnum=1
                                        union all
                                        select t.rnum,t.id,t.amount
                                        ,case when c.runningsum+t.amount > 32 then t.amount else c.runningsum+t.amount end
                                        ,case when c.runningsum+t.amount > 32 then t.id else c.grp end
                                        from cte c
                                        join rownums t on t.rnum=c.rnum+1
                                      )
select grp as id,max(runningsum) as amount
from cte
group by grp

Sample Demo

相关问题