Reputation: 121
I have a table T like this:
ID|DESC1_ID | DESC2_ID | TS | CUM_MONTH_PREV_YEAR| CUM_MONTH_THIS_YEAR|ID2
--------------------------------------------------------------------------|-
1 |1 |1 |31.01.22| | 220 |1
----------------------------------------------------------------------------
2 |1 |2 |31.01.22| | 500 |1
---------------------------------------------------------------------------
3 |1 |3 |31.01.22| | 22 |1
----------------------------------------------------------------------------
4 |2 |1 |31.01.22| | 50 |1
---------------------------------------------------------------------------
5 |1 |1 |01.02.23| | 230 |2
----------------------------------------------------------------------------
6 |1 |2 |01.02.23| | 300 |2
---------------------------------------------------------------------------
7 |1 |3 |01.02.23| | 32 |2
----------------------------------------------------------------------------
8 |2 |1 |01.02.23| | 30 |2
I wish to update the field CUM_MONTH_PREV_YEAR for all entries where id2 is 2. The value should be a previous year value. It could happen, that the date(TS) is not exactly from 1 year before. I have a query below which does what I want.
UPDATE T t1
SET CUM_MONTH_PREV_YEAR = (SELECT NVL(CUM_MONTH_THIS_YEAR , 0)
FROM T t2
WHERE t2.TS = (SELECT MAX(TS)
FROM T
WHERE TS BETWEEN ADD_MONTHS( t1.TS - 7, -12) AND ADD_MONTHS( t1.TS, -12)
AND DESC1_ID = t1.DESC1_ID
AND DESC2_ID = t1.DESC2_ID )
AND t2.DESC1_ID = t.DESC1_ID
AND t2.DESC2_ID = t.DESC2_ID )
WHERE ID2 = 2 ;
I wanted to ask if there is a better way to reach the goal.
UPDATE:
As everything is simplified it happened only by the coincidence that ID2 for previous year is 1 and for this year is 2. In the reality there are much more values.
UPDATE: The values are stored daily(on working days).
Upvotes: 0
Views: 90
Reputation: 7766
UPDATED ANSWER
works on daily bases even if some dates don't exist in previous year. In that case the first date before that is fetched.
UPDATE A_TBL t
SET t.CUM_MONTH_PREV_YEAR = ( Select PREV_CUM
From ( SELECT t.DESC1_ID, t.DESC2_ID, MAX(t.TS) "TS", MAX(t.CUM_MONTH_THIS_YEAR) "PREV_CUM"
FROM A_TBL t
INNER JOIN A_TBL t2 ON(t2.DESC1_ID = t.DESC1_ID And t2.DESC2_ID = t.DESC2_ID)
WHERE To_Number(To_Char(t.TS, 'yyyymmdd')) <= To_Number(To_Char(ADD_MONTHS(t2.TS, -12), 'yyyymmdd'))
GROUP BY t.DESC1_ID, t.DESC2_ID
)
Where DESC1_ID = t.DESC1_ID And DESC2_ID = t.DESC2_ID )
WHERE t.ID2 = 2;
All that you need is the innermost query which gives you the data from the same date or first one before in previous year of that in row with ID2 = 2 (one beeing updated). This is the query:
SELECT t.DESC1_ID, t.DESC2_ID, MAX(t.TS) "TS", MAX(t.CUM_MONTH_THIS_YEAR) "PREV_CUM"
FROM A_TBL t
INNER JOIN A_TBL t2 ON(t2.DESC1_ID = t.DESC1_ID And t2.DESC2_ID = t.DESC2_ID)
WHERE To_Number(To_Char(t.TS, 'yyyymmdd')) <= To_Number(To_Char(ADD_MONTHS(t2.TS, -12), 'yyyymmdd'))
GROUP BY t.DESC1_ID, t.DESC2_ID
DESC1_ID DESC2_ID TS PREV_CUM
---------- ---------- --------- ----------
2 1 31-JAN-22 50
1 2 31-JAN-22 500
1 3 31-JAN-22 22
1 1 31-JAN-22 220
The result after the update is:
Select * From A_TBL;
ID | DESC1_ID | DESC2_ID | TS | CUM_MONTH_PREV_YEAR | CUM_MONTH_THIS_YEAR | ID2 |
---|---|---|---|---|---|---|
1 | 1 | 1 | 31-JAN-22 | 220 | 1 | |
2 | 1 | 2 | 31-JAN-22 | 500 | 1 | |
3 | 1 | 3 | 31-JAN-22 | 22 | 1 | |
4 | 2 | 1 | 31-JAN-22 | 50 | 1 | |
5 | 1 | 1 | 01-FEB-23 | 220 | 230 | 2 |
6 | 1 | 2 | 01-FEB-23 | 500 | 300 | 2 |
7 | 1 | 3 | 01-FEB-23 | 22 | 32 | 2 |
8 | 2 | 1 | 01-FEB-23 | 50 | 30 | 2 |
Upvotes: 1
Reputation: 43626
Looking at your data, I think you are looking for this:
UPDATE table_name A
SET CUM_MONTH_PREV_YEAR = (SELECT B.CUM_MONTH_THIS_YEAR
FROM table_name B
WHERE A.id2 - 1 = B.id2
AND A.DESC1_ID = B.DESC1_ID
AND A.DESC2_ID = B.DESC2_ID);
SELECT *
FROM table_name;
Upvotes: 1