Reputation: 43
I'm trying to calculate using constanta as first value
and then the second row will calculate based on first row calculation result and so on(3rd row using second row result)
the base table look like this, already ordered by date as key
CREATE TABLE T42
("Daytime" timestamp, "A" int, "B" int, "C" int)
;
INSERT ALL
INTO T42 ("Daytime", "A", "B", "C")
VALUES ('01-Apr-2020 12:00:00 AM', -7021, 151.6445, -15)
INTO T42 ("Daytime", "A", "B", "C")
VALUES ('02-Apr-2020 12:00:00 AM', -7037, 152.3164, -15)
INTO T42 ("Daytime", "A", "B", "C")
VALUES ('03-Apr-2020 12:00:00 AM', -7053, 155.0313, -16)
INTO T42 ("Daytime", "A", "B", "C")
VALUES ('04-Apr-2020 12:00:00 AM', -7065, 151.9258, -11)
SELECT * FROM dual
;
For the first april,the constanta is 7005.98.
the result i need should be like this
+----------+-------+-----+-----+---------+----------+
| Daytime | A | B | C | CALC1 | PREV_SAL |
+----------+-------+-----+-----+---------+----------+
| 4/1/2020 | -7021 | 152 | -15 | 7020.98 | 0 |
| 4/2/2020 | -7037 | 152 | -15 | 7035.98 | 7020.98 |
| 4/3/2020 | -7053 | 155 | -16 | 7051.98 | 7035.98 |
| 4/4/2020 | -7065 | 152 | -11 | 7062.98 | 7051.98 |
+----------+-------+-----+-----+---------+----------+
My First try for 1st April is to use this
SELECT "Daytime",
A ,
B ,
C ,
CASE
WHEN "Daytime" = '1-APR-20'
THEN
CASE
WHEN 7005.98 +(C*-1)>7080
THEN 7080
ELSE 7005.98 +(C*-1)
END
ELSE null
END calc1
FROM T42
but then i try using LAG function to get previous result but it error invalid identifier on calc1
SELECT "Daytime",
A ,
B ,
C ,
CASE
WHEN "Daytime" = '1-APR-20'
THEN
CASE
WHEN 7005.98 +(C*-1)>7080
THEN 7080
ELSE 7005.98 +(C*-1)
END
WHEN "Daytime" > '1-APR-20'
THEN
CASE
WHEN calc1 +(C*-1)>7080
THEN 7080
ELSE calc1 +(C*-1)
END
ELSE null
END calc1
FROM T42
I also try using CTE, it good for 2nd april, but for the rest are null
with cte as
(
SELECT "Daytime",
A ,
B ,
C ,
CASE
WHEN "Daytime" = '1-APR-20'
THEN
CASE
WHEN 7005.98 +(C*-1)>7080
THEN 7080
ELSE 7005.98 +(C*-1)
END
END calc1
FROM T42
)
select
cc."Daytime",
A,
B,
C,
cc.calc1,
LAG(cc. calc1, 1, 0) OVER (ORDER BY cc."Daytime") AS prev_sal,
CASE
WHEN cc."Daytime" > '1-APR-20'
THEN
CASE
WHEN LAG(cc. calc1, 1, 0) OVER (ORDER BY cc."Daytime")+(cc.C*-1) >7080
THEN 7080
ELSE LAG(cc. calc1, 1, 0) OVER (ORDER BY cc."Daytime")+(cc.C*-1)
END
END calc2
from cte cc
cte result
+---------+-------+-----+-----+---------+----------+---------+
| Daytime | A | B | C | CALC1 | PREV_SAL | CALC2 |
+---------+-------+-----+-----+---------+----------+---------+
| 00:00.0 | -7021 | 152 | -15 | 7020.98 | 0 | (null) |
| 00:00.0 | -7037 | 152 | -15 | (null) | 7020.98 | 7035.98 |
| 00:00.0 | -7053 | 155 | -16 | (null) | (null) | (null) |
| 00:00.0 | -7065 | 152 | -11 | (null) | (null) | (null) |
+---------+-------+-----+-----+---------+----------+---------+
is it possible to do this kind of calculation?
here my fiddle link
Upvotes: 1
Views: 378
Reputation: 147146
You can generate the results you want with a recursive CTE; first generating a list of row numbers according to Daytime
to make recursion easier, then computing CALC1
from the previous value and the current C
, and PREV_SAL
from the previous CALC1
:
WITH CTE AS (
SELECT T42.*,
ROW_NUMBER() OVER (ORDER BY Daytime) AS rn
FROM T42
),
CTE2 (Daytime, A, B, C, CALC1, PREV_SAL, rn) AS (
SELECT Daytime, A, B, C,
LEAST(7005.98 - C, 7080.0) AS CALC1,
0 AS PREV_SAL,
rn
FROM CTE
WHERE rn = 1
UNION ALL
SELECT c.Daytime, c.A, c.B, c.C,
LEAST(c2.CALC1 - c.C, 7080.0),
c2.CALC1,
c.rn
FROM CTE c
JOIN CTE2 c2 ON c.rn = c2.rn + 1
)
SELECT Daytime, A, B, C, CALC1, PREV_SAL
FROM CTE2
Output:
DAYTIME A B C CALC1 PREV_SAL
2020-04-01 00:00:00.0 -7021 152 -15 7020.98 0
2020-04-02 00:00:00.0 -7037 152 -15 7035.98 7020.98
2020-04-03 00:00:00.0 -7053 155 -16 7051.98 7035.98
2020-04-04 00:00:00.0 -7065 152 -11 7062.98 7051.98
Upvotes: 1