Oracle jobs are a simple way to schedule procedure and processes. However, sometimes the scheduling requirements can get really complicated. A very common request is to run a job on a specific hour on weekdays and not to run it on the weekend. This request can be easily delivered using the “WHAT” parameter of the dbms_job.submit procedure.
begin
if to_char(sysdate, 'D') between 2 and 6 then
my_procedure ;
end if;
end;
However, what will you do if you need to run the procedure at a specific hour on Monday to Friday but on a different hour on the weekend?
In this case you will be happy to know that you can use CASE on the “INTERVAL” parameter of the dbms_job.submit procedure.
declare
my_job number;
begin
dbms_job.submit(job => my_job,
what => 'my_procedure ;',
interval => 'case
when to_number(to_char(sysdate, ''D'')) between 1 and 5 then
TRUNC(SYSDATE+1) + 16 /24
when to_number(to_char(sysdate, ''D'')) between 6 and 7 then
TRUNC(SYSDATE+1) + 8 /24
end'
);
end;
remember that this calculation is for NEXT run not for the current. Therefore, you will need to take into consideration that the timinig for Monday will be calculated on Sunday (I know it sounds obvious but you will be surprised how many time you can do the same mistake).
While the case clause can handle many calculations and complications, there is one caveat. The case statement can handle only 200 characters. This becomes a problem when you try to write a longer statement. For example:
case
when to_number(to_char(sysdate, 'D')) between 1 and 4 then
TRUNC(SYSDATE+1) + 16 /24
when to_number(to_char(sysdate, 'D'))= 5 then
TRUNC(SYSDATE+1) + 13 /24
when to_number(to_char(sysdate, 'D'))= 6 then
TRUNC(SYSDATE+2) + 16 /24
else
TRUNC(SYSDATE+1) + 16 /24
end
if you try to submit a job with this statement, you will probably get the following error
ORA-12899: value too large for column "SYS"."JOB$"."INTERVAL#" (actual: 257, maximum: 200)
ORA-06512: at "SYS.DBMS_IJOB", line 290
ORA-06512: at "SYS.DBMS_JOB", line 159
ORA-06512: at line 4
You can workaround this problem if you use a function to calculate the INTERVAL value.
create or replace function get_next_run_date return date is
res date;
begin
select
case
when to_number(to_char(sysdate, 'D')) between 1 and 4 then
TRUNC(SYSDATE+1) + 16 /24
when to_number(to_char(sysdate, 'D'))= 5 then
TRUNC(SYSDATE+1) + 13 /24
when to_number(to_char(sysdate, 'D'))= 6 then
TRUNC(SYSDATE+2) + 16 /24
else
TRUNC(SYSDATE+1) + 16 /24
end
into res
from dual
;
return res;
end;
once the function is created, all you need to do is use it in your dbms_job submit under the INTERVAL parameter
declare
my_job number;
begin
dbms_job.submit(job => my_job,
what => 'my_procedure ;',
interval => 'get_next_run_date'
);
end