简体   繁体   English

SQL Server:按列总和分组

[英]SQL Server : group by sum of column

I need to aggregate data by one column which contains numeric data. 我需要通过包含数字数据的一列来汇总数据。

I have data like: 我有类似的数据:

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

Result, which I expect is: 结果,我期望是:

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

Query should group data ordered by ID column by Amount column in parts of max sum of amount 32. If amount is greater then 32 then it should be presented as one 'group'. 查询应将按ID列按Amount列最大数量之和的部分中的数据按32分组。如果金额大于32,则应将其表示为一个“组”。 Result should contain Min(ID) and SUM(Amount) which can't be greater than 32 when group more than one record. 结果应包含Min(ID)SUM(Amount) ,当组多个记录时,它们不能大于32。

The only way that I know how to accomplish this is using iteration (although in your case if you have enough single values over 32, then you might be able to use a more efficient approach). 我知道如何完成此操作的唯一方法是使用迭代(尽管在您的情况下,如果您有足够的单个值超过32,那么您也许可以使用更有效的方法)。

Iteration in SQL Server queries is handled by recursive CTEs (once you forswear cursors): 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;

I should note that the use of max(amount) in the outer query assumes that the values are never negative. 我应该注意,在外部查询中使用max(amount)假定值永远不会为负。 A slight modification can handle that situation. 稍加修改即可解决这种情况。

Also, the intermediate result using t is not strictly necessary for the data you have provided. 同样,对于您提供的数据,使用t的中间结果也不是必须的。 It ensures that the columns used in the join actually have no gaps. 它可以确保在使用的列join居然有没有间隙。

You can try this version with rownumbers assigned initially and each row is joined to the previous one in a recursive cte. 您可以尝试使用最初分配的行号尝试此版本,并且在递归cte中将每一行连接到上一行。 And if the running sum > 32 a new group starts. 如果运行总和> 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

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

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