Есть несколько способов приблизиться к этому, но вы можете использовать оконные аналитические функции c, чтобы получить промежуточную сумму дефицита и того, сколько бюджета было потрачено. Чтобы получить конечный номер, который вы хотите, вы можете использовать что-то вроде:
greatest(deficit,
sum(deficit) over (order by date_col)
+ least(100, - sum(deficit) over (order by date_col)))
или, возможно, немного более четко:
case
when sum(deficit)
over (order by date_col rows between unbounded preceding and 1 preceding) <= -100
then
deficit
else
sum(deficit) over (order by date_col)
+ least(100, - sum(deficit) over (order by date_col))
end
sum(deficit) over (order by date_col)
дает вам промежуточный итог в дате порядок, дефицитов. Для первой даты, которая рассчитывается как -5; для второго как (-5 + -7) = -12; et c.
least(100, - sum(deficit) over (order by date_col)))
дает вам бюджет, использованный до текущей даты включительно, но ограниченный 100. Для первой даты least(100, - (-5))
, которая равна 5; для второго это least(100, - (-5 + -7))
, что составляет 12; к 20-му это least(100, - (-102))
, так что вы получаете наименьшее из 100 и 102 - таким образом, ограниченное до 100. (Вы можете сделать это как greatest(-100, sum(deficit) over (order by date_col)))
, если хотите, а затем вместо этого вычесть это на последнем шаге.)
Когда это добавляется к промежуточному итогу дефицита, первые несколько строк удаляются, и вы получаете ноль. Для 20-го сумма дефицита равна 102, а ограниченное значение равно 100, так что в итоге вы получите -2. Для 30-го это даст вам 100 - 108, то есть -8 вместо -6, который вы на самом деле хотите. Вот тут и приходит greatest(deficit, ...)
. До 20 числа это не меняет ответа; greatest(-8, 100 - 102)
по-прежнему -2, потому что -2> -8. Для 30 числа у вас greatest(-6, 100 - 108)
равно -6, потому что -6> -8.
Демонстрация с некоторыми примерами данных и демонстрацией некоторых из рабочих:
-- sample data
with your_table (date_col, deficit) as (
select date '2020-01-01', -5 from dual
union all select date '2020-01-02', -7 from dual
union all select date '2020-01-03', -50 from dual
union all select date '2020-01-04', -32 from dual
union all select date '2020-01-20', -8 from dual
union all select date '2020-01-30', -6 from dual
)
-- actual query
select date_col, deficit,
sum(deficit) over (order by date_col) as sum_deficit,
least(100, - sum(deficit) over (order by date_col)) as budget_used,
greatest(0, 100 + sum(deficit) over (order by date_col)) as budget_left_1,
100 - least(100, - sum(deficit) over (order by date_col)) as budget_left_2,
greatest(deficit,
sum(deficit) over (order by date_col)
+ least(100, - sum(deficit) over (order by date_col))) as new_deficit_1,
case
when sum(deficit)
over (order by date_col rows between unbounded preceding and 1 preceding) <= -100
then
deficit
else
sum(deficit) over (order by date_col)
+ least(100, - sum(deficit) over (order by date_col))
end as new_deficit_2
from your_table
order by date_col;
, которая производит:
DATE_COL DEFICIT SUM_DEFICIT BUDGET_USED BUDGET_LEFT_1 BUDGET_LEFT_2 NEW_DEFICIT_1 NEW_DEFICIT_2
---------- ---------- ----------- ----------- ------------- ------------- ------------- -------------
2020-01-01 -5 -5 5 95 95 0 0
2020-01-02 -7 -12 12 88 88 0 0
2020-01-03 -50 -62 62 38 38 0 0
2020-01-04 -32 -94 94 6 6 0 0
2020-01-20 -8 -102 100 0 0 -2 -2
2020-01-30 -6 -108 100 0 0 -6 -6