I am Trying to create a view based on a business calendar table called Business Payment Calendar view with two new calculated columns:
- Payment Warning Date (
Payment_Warning_Date
) - Payment Due Date (
Payment_Due_Date
)
And, also the non-calculated Transaction_Date
Those dates are based on the number of BUSINESS days from the transaction date from the business calendar, 7 and 10 business days. The Business Calendar table contains columns populated for the year.
CAL_Date (which is our datestamp),
Day_Name,
Month_Name,
Cal_Year,
Month_Num,
Weekend (True/False),
Holiday (True/False),
Bus_Working_Day (True/False).
So for example, say you have a purchase today, the output will be:
Transaction_Date: 6/26/2017
Payment Warning Date: 7/6/2017
Payment Due Date: 7/11/2017
Figure we have the weekend coming up, next Monday (July 3) is a work day, but Tuesday (July 4) is a US holiday, then 3 more work days.
I'm just not having any luck building a case statement that properly takes into account the Bus_Working_Day field for SYSDATE+7 and +10 and then return the correct date.
Best Answer
The following will generate a list showing the current date, and the warning and due dates for the current date.
dbfiddle here
It requires more than a CASE statement, because you need to evaluate whether each following day is a business day or not to find the days you need.
Here's how it works: - join the table against itself (with
mn
as the first instance andalt
as the second); - ignore allalt
rows where thealt
date is less than or equal to themn
date (because the warning and due date will always come after the current date, of course), and where thealt
date is not a business working day; - for eachmn
date, number thealt
dates in ascending order; - take the calendar table, and outer join it to the results of the above twice (joining to themn
date) aswarn
anddue
; - for the join towarn
, take the 7thalt
date where the calendar date matches themn
date, fordue
, the 10thalt
date.You may want to consider (if possible) adding
warning_date
anddue_date
to the existing calendar table - you could modify the code above to populate the values, once the base information on the dates is in place. Saves you from joining the calendar table to itself five times to get what you want. (OK, if you have a specific date, then you can hit thewarn
anddue
subqueries directly, and don't really have to join back to the calendar table - I did that for demonstration purposes. So, only joining it to itself 4 times).NOTE: In newer versions of Oracle, where
CROSS APPLY
andOUTER APPLY
are available, you may be able to change these to a more direct (and possibly better performing) query - however, without knowing what version you've got available (and needing to use dbfiddle for my testing, where the version is 11g), I went with this solution.You should be able to modify this to meet your needs.
UPDATE: You asked what changes would need to be made to use the query in a trigger.
Actually, now that I think about it, I'd be inclined not to use a trigger directly. You see, even if one row is added, all the rows (or, at least, all the rows whose date is, say, within 20 days before any changed date) will need to be updated - which would mean we'd have a trigger that was (technically, at least) recursive.
To avoid that, it might be better to do something somewhat more complicated (of course!).
FLAG_JOB_TO_RUN
, and give it one column,JOB_NAME
.INSERT
the valueUpdate_Warn_Due_Dates
intoFLAG_JOB_TO_RUN.JOB_NAME
(if it doesn't already exist).Schedule a script (or, even better, create a stored procedure and schedule that) to do the following:
FLAG_JOB_TO_RUN
UPDATE
version of theSELECT
query above to setWarning_Date
andDue_Date
for all rows inmyCal
, andDELETE
that row fromFLAG_JOB_TO_RUN
Run this job as often as you think is necessary. It might suffice to run it once a night, and to manually run it right after you know there's been a major change; or, you might need to run it every 5 minutes.