Reputation: 3315
I'm trying to do the following WITHOUT CURSORS. Is it possible?
I have this variable:
DECLARE @Amount MONEY = 800;
Sample table that I current have:
EntryID Amount
--------------------------------------------
1 200
2 250
3 600
4 100
... ....(could be many more rows)
I want to be able to update the table to only show the "Amount" that it needs to add up to the @Amount variable ($800). So I'd like the table to end up like this:
EntryID Amount
--------------------------------------------
1 200 (uses up full 200)
2 250 (uses up full 250)
3 350 (uses up 350 of the 600)
OR LIKE THIS
EntryID Amount Distrib
--------------------------------------------
1 200 200
2 250 250
3 600 350
4 100 0
... ... ...
So the SUM()
is equal to @Amount
Thanks in advance!
PS - I'm doing this in SQL Server 2012
UPDATE:
Here's my final solution. Thanks again, Gordon:
DECLARE @Amount money = 800;
DECLARE @tmpPaymentDist TABLE (EntryID INT, Amount MONEY, Distrib MONEY);
INSERT INTO @tmpPaymentDist (EntryID, Amount) VALUES (1, 200);
INSERT INTO @tmpPaymentDist (EntryID, Amount) VALUES (2, 250);
INSERT INTO @tmpPaymentDist (EntryID, Amount) VALUES (3, 600);
INSERT INTO @tmpPaymentDist (EntryID, Amount) VALUES (4, 100);
with toupdate as (
select t.*,
(case when sum(amount) over (order by entryid) <= @amount
then amount
when sum(amount) over (order by entryid) < @amount + amount
then @amount - (sum(amount) over (order by entryid) - amount)
else 0
end) as new_distrib
from @tmpPaymentDist t
)
update T set distrib = new_distrib
FROM @tmpPaymentDist T
INNER JOIN toupdate T2 ON T2.EntryID = T.EntryID
WHERE T2.new_distrib > 0
SELECT * FROM @tmpPaymentDist
Upvotes: 2
Views: 151
Reputation: 1270463
Yes, you can do this without cursors, using cumulative sums:
select t.*,
(case when sum(amount) over (order by entryid) <= @amount
then amount
when sum(amount) over (order by entryid) < @amount + amount
then @amount - (sum(amount) over (order by entryid) - amount)
else 0
end) as distrib
from table t;
That is, use cumulative sums for the calculation.
For an update
, you can use the same logic:
with toupdate as (
select t.*,
(case when sum(amount) over (order by entryid) <= @amount
then amount
when sum(amount) over (order by entryid) < @amount + amount
then @amount - (sum(amount) over (order by entryid) - amount)
else 0
end) as new_distrib
from table t
)
update toudpate
set distrib = new_distrib;
Upvotes: 3