• Using the sample data provided, a simple calculation rCTE works fine with both positive and negative numbers.

    DECLARE @AmountToAllocate INT = 21

    ;WITH Calculator AS (

    SELECT

    BucketID, TotalSize, Amount,

    AmountLeftToAllocate = CASE

    WHEN @AmountToAllocate > (TotalSize - Amount) THEN @AmountToAllocate - (TotalSize - Amount)

    WHEN @AmountToAllocate < 0 AND ABS(@AmountToAllocate) > Amount THEN Amount + @AmountToAllocate

    ELSE 0 END,

    NewAmount = CASE

    WHEN @AmountToAllocate > (TotalSize - Amount) THEN TotalSize

    WHEN @AmountToAllocate < 0 AND ABS(@AmountToAllocate) > Amount THEN 0

    ELSE Amount + @AmountToAllocate END

    FROM dbo.Buckets

    WHERE BucketID = 1

    UNION ALL

    SELECT

    tr.BucketID, tr.TotalSize, tr.Amount,

    AmountLeftToAllocate = CASE

    WHEN lr.AmountLeftToAllocate > (tr.TotalSize - tr.Amount) THEN lr.AmountLeftToAllocate - (tr.TotalSize - tr.Amount)

    WHEN lr.AmountLeftToAllocate < 0 AND ABS(lr.AmountLeftToAllocate) > tr.Amount THEN tr.Amount + lr.AmountLeftToAllocate

    ELSE 0 END,

    NewAmount = CASE

    WHEN lr.AmountLeftToAllocate > (tr.TotalSize - tr.Amount) THEN tr.TotalSize

    WHEN lr.AmountLeftToAllocate < 0 AND ABS(lr.AmountLeftToAllocate) > tr.Amount THEN 0

    ELSE tr.Amount + lr.AmountLeftToAllocate END

    FROM dbo.Buckets tr

    INNER JOIN Calculator lr ON lr.BucketID + 1 = tr.BucketID

    )

    SELECT

    BucketID,

    TotalSize,

    Amount = NewAmount,

    OldAmount = Amount

    FROM Calculator

    “Write the query the simplest way. If through testing it becomes clear that the performance is inadequate, consider alternative query forms.” - Gail Shaw

    For fast, accurate and documented assistance in answering your questions, please read this article.
    Understanding and using APPLY, (I) and (II) Paul White
    Hidden RBAR: Triangular Joins / The "Numbers" or "Tally" Table: What it is and how it replaces a loop Jeff Moden