I have created dummy table with following data:
<table>
<tr>
<th>PRODUCT</th>
<th>FROM_DATE</th>
<th>VALID_TO</th>
</tr>
<tr>
<td>ABC</td>
<td>18-Jan-2016</td>
<td>31-Dec-9999</td>
</tr>
<tr>
<td>ABC</td>
<td>01-Feb-2016</td>
<td>31-Dec-9999</td>
</tr>
<tr>
<td>DEF</td>
<td>01-Aug-2016</td>
<td>31-Dec-9999</td>
</tr>
<tr>
<td>DEF</td>
<td>01-Sep-2016</td>
<td>31-Dec-9999</td>
</tr>
<tr>
<td>GHI</td>
<td>01-Mar-2016</td>
<td>31-Dec-9999</td>
</tr>
</table>
The following block will update the date according to your requirement. Using LAG and LEAD function you can access more than one row without joining the same table. LAG is used to access the previous row and LEAD is used to access the next row.
BEGIN
FOR I IN (SELECT NVL(LEAD(T.FROM_DATE)
OVER(PARTITION BY T.PRODUCT ORDER BY T.FROM_DATE) - 1,
T.VALID_TO) NEW_VALID_TO,
PRODUCT,
FROM_DATE
FROM PRODUCT_TABLE T) LOOP
UPDATE PRODUCT_TABLE A
SET A.VALID_TO = I.NEW_VALID_TO
WHERE A.PRODUCT = I.PRODUCT
AND A.FROM_DATE = I.FROM_DATE;
COMMIT;
END LOOP;
END;
The output will be as shown below:
<table>
<tr>
<th>PRODUCT</th>
<th>FROM_DATE</th>
<th>VALID_TO</th>
</tr>
<tr>
<td>ABC</td>
<td>18-Jan-2016</td>
<td>31-Jan-2016</td>
</tr>
<tr>
<td>ABC</td>
<td>01-Feb-2016</td>
<td>31-Dec-9999</td>
</tr>
<tr>
<td>DEF</td>
<td>01-Aug-2016</td>
<td>31-Aug-2016</td>
</tr>
<tr>
<td>DEF</td>
<td>01-Sep-2016</td>
<td>31-Dec-9999</td>
</tr>
<tr>
<td>GHI</td>
<td>01-Mar-2016</td>
<td>31-Dec-9999</td>
</tr>
</table>