Is ther any clear way of doing the following in one SQL (PL) code? 🙂
What I have in the tables is the following:
CONTACT_TBL (HEADER)
CONTRACT_ID | BEGIN_DATE | END_DATE | TOT_AMOUNT |
---|---|---|---|
123 | 13-MAY-16 | 12-MAY-34 | 100 |
456 | 13-JAN-14 | 12-DEC-25 | 300 |
789 | 13-SEP-14 | 12-OCT-34 | 700 |
CONTRACT_ACTIVTY (DETAIL)
CONTRACT_ID | SEQNUM | END_DATE | AMOUNT | COMMENTS |
---|---|---|---|---|
123 | 1 | 12-MAY-19 | 25 | 25 – Initial Expiration |
123 | 2 | 12-MAY-24 | 25 | 25 |
123 | 3 | 12-MAY-29 | 25 | 25 |
123 | 4 | 12-MAY-34 | 25 | 25 – End of Contract |
What we need is to populate for each row:
- BEGIN_DATE
- For SEQNUM #1 – BEGIN_DATE is always CONTACT_TBL.BEGIN_DATE (in this case 13-MAY-15, a 3 year span)
- For SEQNUM #2 to N – BEGIN_DATE is 1 day more than previous row’s END_DATE (in this case 12-MAY-19 + 1 = 13-MAY-19, all 5 year spans)
- Mark the row ‘Active’ if the SYSDATE is between BEGIN_DATE and END_DATE (in this case it’s Row #2)
CONTRACT_ID | SEQNUM | BEGIN_DATE | END_DATE | AMOUNT | STATUS |
---|---|---|---|---|---|
123 | 1 | 13-MAY-16 | 12-MAY-19 | 25 | |
123 | 2 | 13-MAY-19 | 12-MAY-24 | 25 | Active |
123 | 3 | 13-MAY-24 | 12-MAY-29 | 25 | |
123 | 4 | 13-MAY-29 | 12-MAY-34 | 25 |
2
Answers
Hope below snippet serve the purpose.
N.B. This answer assumes the db is Oracle
This can be done by using
LAG
to find the date from the previous row.LAG
can accept 3 parameters, the first of which is the column whose value you want to find from the previous row, the second is how many rows to go back each time (default is 1), and the third is what to display if there is no previous row found.In your case, you want to default to the begin_date from the
contact_tbl
if there is no previous row to the first row in thecontract_activity
table, so you need to join the two tables as well, like so:Your
status
column is a simple case expression, but since it refers to the calculated begin_date, rather than repeating the calculation, I did the begin_date calculation in one subquery, and then referenced that in the outer query.Note how I used
TRUNC(sysdate)
instead of justsysdate
in the case expression for thestatus
– DATEs in Oracle have a time component (which defaults to midnight if you don’t specify the time), so if you ran the query any time between12/05/2024 00:00:01
and12/05/2024 23:59:59
, your query wouldn’t return a status ofActive
for the second row if you usedsysdate
. You need to explicitly truncatesysdate
to midnight in order for the comparison to work.