Our DB is Oracle 11g. I have a table with the structure is as shown below:
Person_Id | Eff_Dt | Wid | Prv_Wid
----------------------------------
P1 | 1/1/2001 | 2001 |
P1 | 1/10/2001 | 2001 |
P1 | 10/10/2001 | 2002 |
P1 | 1/1/2002 | 2003 |
P1 | 5/4/2002 | 2003 |
P1 | 8/6/2002 | 2002 |
P1 | 1/1/2005 | 2001 |
P1 | 1/10/2006 | 2001 |
I have a requirement that the Prv_Wid should be derived from the previous row's WID. But if the current and previous WIDs are same, then I have to go to the old previous row where the WID is different and put it in my current row's Prv_Wid.
It should be as shown below:
Person_Id | Eff_Dt | Wid| Prv_Wid
----------------------------
P1 | 1/1/2001 | 2001 | 0
P1 | 1/10/2001 | 2001 | 0
P1 | 10/10/2001 | 2002 | 2001
P1 | 1/1/2002 | 2003 | 2002
P1 | 5/4/2002 | 2003 | 2002
P1 | 8/6/2002 | 2002 | 2003
P1 | 1/1/2005 | 2001 | 2002
P1 | 1/10/2006 | 2001 | 2002
I have tried several ways like lead, lag, first_value, last_value and procedure to achieve. But, I am not successful. Could you please provide any solution?
Best Answer
All right, so we need some mechanism to keep track of the previous wid value regardless of the number of repeating values, so we can not use
LAG
directly, because we do not know how far back was the last different value.Our data is:
I will not repeat the
with
section any more to save space. Let's calculate a new field, calledprev_marker
as:If
wid = previous wid
, this field becomesNULL
. Ifwid != previous wid
, this field gets the value of the previouswid
Using this coluumn, we can get the desired
prv_wid
value with theLAST_VALUE
function if we inspect rows up to the current row. The trick is, that theLAST_VALUE
function supports theIGNORE NULLS
option, so when we encounter aNULL
value, we can easily ignore all the rows with the samewid
and fall back to the previous value:Our last task is to replace the
NULL
s with0
s, that is just a simpleNVL
: