Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQL Aggregate Sum to Only Net Out Negative Rows

Tags:

sql

sql-server

I'm trying to roll up product values based on dates. The example below starts out with 20,000, adds 5,000, and then subtracts 7,000. The result should be eating through the entire 5,000 and then into the prior positive row. This would remove the 5,000 row.

I think this would be as simple as doing a sum window function ordered by date descending. However, as you can see below, I want to stop summing at any row that remains positive and then move to the next.

I cannot figure out the logic in SQL to make this work. In my head, it should be:

SUM(Value) OVER (PARTITION BY Product, (positive valued rows) ORDER BY Date DESC)

But there could be multiple positive valued rows in a row where a negative valued row could eat through all of them, or there could be multiple negative values in a row.

This post seemed promising, but I don't think the logic would work for if a negative value would be larger than the positive value.

HAVE:

+------------+----------------+-------+
|    Date    |    Product     | Value |
+------------+----------------+-------+
| 01/13/2015 | Prod1          | 20000 |
| 08/13/2015 | Prod1Addition1 |  5000 |
| 12/13/2015 | Prod1Removal   | -7000 |
| 02/13/2016 | Prod1Addition2 |  2000 |
| 03/13/2016 | Prod1Addition3 |  1000 |
| 04/13/2016 | Prod1Removal   | -1500 |
+------------+----------------+-------+

WANT:

+------------+----------------+-------+
|    Date    |    Product     | Value |
+------------+----------------+-------+
| 01/13/2015 | Prod1          | 18000 |
| 02/13/2016 | Prod1Addition2 |  1500 |
+------------+----------------+-------+
like image 651
houstonwp Avatar asked Feb 01 '26 11:02

houstonwp


1 Answers

i can only think of a recursive cte solution

; with 
cte as
(
    select  Date, Product, Value, rn = row_number() over (order by Date)
    from    yourtable
),
rcte as
(
    select  Date, Product, Value, rn, grp = 1
    from    cte 
    where   rn  = 1
    union all
    select  Date    = case when r.Value < 0 then c.Date else r.Date end, 
        Product = case when r.Value < 0 then c.Product else r.Product end, 
        c.Value, 
        c.rn, 
        grp = case when r.Value < 0 then r.grp + 1 else r.grp end
    from    rcte r
        inner join cte c    on  r.rn    = c.rn - 1
)
select  Date, Product, Value = sum(Value)
from    rcte
group by Date, Product, grp     
order by Date
like image 123
Squirrel Avatar answered Feb 03 '26 03:02

Squirrel



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!