简体   繁体   中英

SQL query to group based on sum

I have a simple table with values that I want to chunk/partition into distinct groups based on the sum of those values (up to a certain limit group sum total).

eg,. imagine a table like the following:

Key   Value
-----------
A         1
B         4
C         2
D         2
E         5
F         1

And I would like to group into sets such that no one grouping's sum will exceed some given value (say, 5).

The result would be something like:

Group  Key    Value
-------------------
1      A          1     
       B          4
           --------  
           Total: 5     

2      C          2
       D          2
           --------
           Total: 4

3      E          5
           --------
           Total: 5

4      F          1
           --------
           Total: 1

Is such a query possible?

While I am inclined to agree with the comments that this is best done outside of SQL, here is some SQL which would seem to do roughly what you're asking:

with mytable AS (
    select 'A' AS [Key], 1 AS [Value] UNION ALL
    select 'B', 4 UNION ALL
    select 'C', 2 UNION ALL
    select 'D', 2 UNION ALL
    select 'E', 5 UNION ALL
    select 'F', 1
)
, Sums AS (
    select T1.[Key] AS T1K
        , T2.[Key] AS T2K
        , (SELECT SUM([Value])
           FROM mytable T3
           WHERE T3.[Key] <= T2.[Key]
           AND T3.[Key] >= T1.[Key]) AS TheSum
    from mytable T1
    inner join mytable T2
        on T2.[Key] >= T1.[Key]
)
select S1.T1K AS StartKey
    , S1.T2K AS EndKey
    , S1.TheSum
from Sums S1
left join Sums S2
    on (S1.T1K >= S2.T1K and S1.T2K <= S2.T2K)
    and S2.TheSum > S1.TheSum
    and S2.TheSum <= 5
where S1.TheSum <= 5
AND S2.T1K IS NULL

When I ran this code on SQL Server 2008 I got the following results:

StartKey    EndKey    Sum
A           B         5
C           D         4
E           E         5
F           F         1

It should be straightforward to construct the required groups from these results.

If you want to have only two members or less in each set, you can use the following query:

Select
  A.[Key] as K1 ,
  B.[Key] as K2 ,
  isnull(A.value,0) as V1 ,
  isnull(B.value,0) as V2 ,
  (A.value+B.value)as Total
from Table_1 as A left join Table_1 as B
on A.value+B.value<=5 and  A.[Key]<>B.[Key]

For finding sets having more members, you can continue to use joins.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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