For context:
I am playing with a filling level sensor, a water tank and a watering pump and have the following problem:
I have an initial filling value for my tank.
Each time step, I am subtracting a certain amount (the outflow) from this init value via a window function, in order to get a time series with the filling level.
Should that running sum get below a lower threshold, it gets "refilled" to an upper threshold for the refill.
From there, I want to keep subtracting until it hits the lower value again, then refill, etc.
I would like to sum up the refill amount over the series
Something like the following:
Image may be NSFW.
Clik here to view.
Assuming I start from 10, and refill from 5 as lower limit to 8 as upper limit. The table should look something like this, with running sum
being the amount of water in the tank, refill_amount
as the amount that was needed to refill, and/or refill_running_sum
to get a final, total amount for refilling:
time_step | running_sum | refill_amount | refill_running_sum | ----------+-------------+---------------+----------------------| 1 10 0 0 2 9 0 0 3 8 0 0 4 7 0 0 5 6 0 0 6 - - - 5 - - - 3 - - - - 3 - --refill 7 8 0 3 8 7 0 3 9 6 0 3 10 - - - 5 - - - 3 - - - - 6 - --refill 11 8 0 6 12 7 0 6 13 6 0 6 14 - - - 5 - - - 3 - - - - 9 - --refill 15 8 0 9
I got as far as the SQL below dbfiddle here:
Using a CASE
statement, I get to refill the amount once and get the first amount of water to refill. But I would need a CTE with a case for every single refill.
Apologies as I know I'm missing SQL vocabulary here to properly approach this. Yet thank you for any pointers!
/* Generate some mockup series with init+threshold limits */ WITH vals AS ( SELECT generate_series(1,30,1) AS time_step ,10 AS init_val ,8 AS upper_limit_refill ,5 AS lower_limit_refill ,random() AS random_val ), /* Create the window function subtracting a mockup val */ example_series AS ( SELECT * ,init_val-sum(random_val) OVER(ORDER BY time_step ASC) AS running_amount FROM vals ) SELECT time_step ,running_amount /* I manage to get the amount needed to refill ONCE, but I'd need a new CTE and CASE for each refill like this*/ ,CASE WHEN running_amount < lower_limit_refill THEN upper_limit_refill + running_amount -sum(random_val) OVER(ORDER BY time_step ASC ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) ELSE 0 END AS refill_once ,CASE WHEN running_amount < lower_limit_refill THEN upper_limit_refill - running_amount ELSE 0 END AS refill_to_limit_amount FROM example_series