1

I have table invoice which looks like this:
enter image description here

And I have 2000 as amount of money that I want to reduce it from these invoices one by one and when the amount of money is over I want the query to stop like this:
invoice with id = 2 --> 1500 < 2000 --> so the paid_money becomes 0
and the rest of amount of money is: 2000 - 1500 = 500 (still > 0 so we continue to the next invoice)
invoice with id = 1 -->1500.2 > 500 --> so the paid_money becomes 1500.2 - 500 = 1000.2
and the rest of the amount of money = 0 (this is the condition where I want to stop the update query)
The order of update is ORDER BY id DESC.
And thnx for your help.

2 Answers 2

1

First of all I doubt it could be done with single SQL command because of need of specific order. You should write PL/pgSQL procedure to iterate rows in order, do the logic and modification per row and terminate execution in right moment.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you, I wanted to know if there is an easy way to do this but you make it clear to me :)
I suspect it can be done with a recursive CTE that determines which rows to allocate what funds to, then a separate CTE term that actually applies those decisions.
0

There are so many ways of doing that. Here is one with a single sql (without creating any function or procedure):

-- creates the invoice table for testing
drop table if exists invoice;
create table invoice (id integer primary key, value numeric, paid_value numeric, money_remaining numeric);
-- inserts invoices data
insert into invoice  (id, value, paid_value, money_remaining) values (1, 500, 0, 0), (2, 700, 0, 0), (3, 1000, 0, 0); 

with 
-- computes the total of money necessary to pay all invoices including the current one
-- acc_value = sum of all invoices where id is less or equals to the current invoice
a as 
(
select  i.id, i.value, (select sum(value) from invoice i1 where i1.id <= i.id) acc_value
from    invoice i
),

-- computes the total of money spent
b as 
(
select  *, (2000 - acc_value) as money_remaining
         , case when (2000 - acc_value) >= 0 then value else 0 end as paid_value
from    a
)

-- updates each invoice with it's computed values
update invoice i
   set paid_value = b.paid_value,
       money_remaining = case when b.money_remaining < 0 then (i.value + b.money_remaining) else b.money_remaining end
from b
where i.id = b.id;

-- shows the result
select * from invoice;

1 Comment

Very nice, thnx for your help :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.