The answer to this previous question demonstrates a method to select rows until a cumulative threshold is reached:
select t.*
from (
select t.*, sum(amount) over (order by date desc) as running_amount from t
) t
where running_amount - amount < 12
order by date desc;
Now assume that what I want to do is perform an update on the result from that query. Maybe it looks something like this:
update t
set owner=$OWNER
from (
select t.*, sum(amount) over (order by date desc) as running_amount
from t
where owner is null
) t
where t.running_amount - t.amount < 12
order by date desc;
Now assume that many such queries are run concurrently. I expect we may have a race condition because if the subquery runs at the same time it will return the same set of results in the same order to two or more outer queries, meaning the outer queries either tries to change the same rows, or the running amount is incorrect so it ends up selecting the wrong rows.
I'm not sure FOR UPDATE SKIP LOCKED helps here. If I use it in the above query I'll get a "FOR UPDATE is not allowed with window functions" error. But even if I could use it, using it in the subquery would end up locking every single row which is not what I want. Using it in the outer query I think is applying the lock in the wrong place.
So I thought I'd turn to greater brains than mine to see if you can help point me in the right direction?
- Is my intuition correct in that the above query will result in race conditions when run concurrently?
- Is there a better and safer approach to this problem?