Skip to Main Content
  • Questions
  • Change a DBMS_SCHEDULER job's next run date

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question, Peter.

Asked: October 19, 2017 - 4:48 pm UTC

Last updated: June 16, 2018 - 1:20 am UTC

Version: 11.2.0.4.0

Viewed 50K+ times! This question is

You Asked

I have a job scheduled via DBMS_SCHEDULER. It is scheduled to run weekly. It has been running fine for some time now. All I want to do is alter the next_run_date. I cannot find any way to do this in the documentation. I can alter the original start date using SET_ATTRIBUTE, attribute_name => 'START_DATE', although it seems crazy to me how useful it is to alter history.

Is there no way to change the next_run_date short of dropping and recreating the job?

and Connor said...

Not sure what you mean by

although it seems crazy to me how useful it is to alter history

I would not be using "start_date" as the record of anything in the scheduler, but the actual history of when the job was run, ie

DBA_SCHEDULER_JOB_LOG
DBA_SCHEDULER_JOB_RUN_DETAILS

and the like. Or CREATED in xxx_OBJECTS for when the job was created. START_DATE is merely a mechanism to establish the schedule.

If you really wanted the schedule to "document" its own history, you could do something like:

--
-- initial weekly schedule which we expect to run forever (which is assigned to whatever jobs we need)
--
SQL> begin
  2    dbms_scheduler.create_schedule (
  3      schedule_name   => 'assumed_forever',
  4      start_date      => sysdate,
  5      repeat_interval => 'freq=weekly',
  6      end_date        => null);
  7  end;
  8  /

PL/SQL procedure successfully completed.

SQL>
SQL> set serveroutput on size 999999
SQL>
SQL> declare
  2        l_start_date TIMESTAMP;
  3        l_next_date TIMESTAMP;
  4        l_return_date TIMESTAMP;
  5      begin
  6        l_start_date := trunc(SYSTIMESTAMP);
  7        l_return_date := l_start_date;
  8
  9        for ctr in 1..30 loop
 10         dbms_scheduler.evaluate_calendar_string(
 11           'assumed_forever',
 12           l_start_date, l_return_date, l_next_date
 13           );
 14         dbms_output.put_line('Next Run on: ' ||
 15           to_char(l_next_date,'mm/dd/yyyy hh24:mi:ss')
 16           );
 17         l_return_date := l_next_date;
 18       end loop;
 19     end;
 20  /
Next Run on: 10/20/2017 11:58:27
Next Run on: 10/27/2017 11:58:27
Next Run on: 11/03/2017 11:58:27
Next Run on: 11/10/2017 11:58:27
Next Run on: 11/17/2017 11:58:27
Next Run on: 11/24/2017 11:58:27
Next Run on: 12/01/2017 11:58:27
Next Run on: 12/08/2017 11:58:27
Next Run on: 12/15/2017 11:58:27
Next Run on: 12/22/2017 11:58:27
Next Run on: 12/29/2017 11:58:27
Next Run on: 01/05/2018 11:58:27
Next Run on: 01/12/2018 11:58:27
Next Run on: 01/19/2018 11:58:27
Next Run on: 01/26/2018 11:58:27
Next Run on: 02/02/2018 11:58:27
Next Run on: 02/09/2018 11:58:27
Next Run on: 02/16/2018 11:58:27
Next Run on: 02/23/2018 11:58:27
Next Run on: 03/02/2018 11:58:27
Next Run on: 03/09/2018 11:58:27
Next Run on: 03/16/2018 11:58:27
Next Run on: 03/23/2018 11:58:27
Next Run on: 03/30/2018 11:58:27
Next Run on: 04/06/2018 11:58:27
Next Run on: 04/13/2018 11:58:27
Next Run on: 04/20/2018 11:58:27
Next Run on: 04/27/2018 11:58:27
Next Run on: 05/04/2018 11:58:27
Next Run on: 05/11/2018 11:58:27

PL/SQL procedure successfully completed.
--
-- now we want the run in (say) 15 days time to be the last, and then we pause and not run again until a 30 days from noe
-- but we dont want to lose track that we're doing this.
-- So first I'll mark an end date for our current schedule
--
SQL> begin
  2    dbms_scheduler.set_attribute (
  3      name      => 'assumed_forever',
  4      attribute => 'end_date',
  5      value     => sysdate+15);
  6  end;
  7  /

PL/SQL procedure successfully completed.

--
-- and create a schedule to pick up at our desired new starting point
--
SQL> begin
  2    dbms_scheduler.create_schedule (
  3      schedule_name   => 'next_start_point',
  4      start_date      => sysdate+30,
  5      repeat_interval => 'freq=weekly',
  6      end_date        => null);
  7  end;
  8  /

PL/SQL procedure successfully completed.

--
-- Now combine the two schedules to give a complete picture
--
SQL> begin
  2    dbms_scheduler.create_schedule (
  3      schedule_name   => 'combined',
  4      start_date      => sysdate,
  5      repeat_interval => 'assumed_forever,next_start_point',
  6      end_date        => null);
  7  end;
  8  /

PL/SQL procedure successfully completed.

--
-- which we would then assign to our job(s)
-- And we can how that would equate to job executions
--
SQL> set serveroutput on size 999999
SQL>
SQL> declare
  2        l_start_date TIMESTAMP;
  3        l_next_date TIMESTAMP;
  4        l_return_date TIMESTAMP;
  5      begin
  6        l_start_date := trunc(SYSTIMESTAMP);
  7        l_return_date := l_start_date;
  8
  9        for ctr in 1..30 loop
 10         dbms_scheduler.evaluate_calendar_string(
 11           'combined',
 12           l_start_date, l_return_date, l_next_date
 13           );
 14         dbms_output.put_line('Next Run on: ' ||
 15           to_char(l_next_date,'mm/dd/yyyy hh24:mi:ss')
 16           );
 17         l_return_date := l_next_date;
 18       end loop;
 19     end;
 20  /
Next Run on: 10/20/2017 12:06:38
Next Run on: 10/27/2017 12:06:38
Next Run on: 11/03/2017 12:06:38

(then we skipped a week as expected)

Next Run on: 11/19/2017 12:07:38
Next Run on: 11/26/2017 12:07:38
Next Run on: 12/03/2017 12:07:38
Next Run on: 12/10/2017 12:07:38
Next Run on: 12/17/2017 12:07:38
Next Run on: 12/24/2017 12:07:38
Next Run on: 12/31/2017 12:07:38
Next Run on: 01/07/2018 12:07:38
Next Run on: 01/14/2018 12:07:38
Next Run on: 01/21/2018 12:07:38
Next Run on: 01/28/2018 12:07:38
Next Run on: 02/04/2018 12:07:38
Next Run on: 02/11/2018 12:07:38
Next Run on: 02/18/2018 12:07:38
Next Run on: 02/25/2018 12:07:38
Next Run on: 03/04/2018 12:07:38
Next Run on: 03/11/2018 12:07:38
Next Run on: 03/18/2018 12:07:38
Next Run on: 03/25/2018 12:07:38
Next Run on: 04/01/2018 12:07:38
Next Run on: 04/08/2018 12:07:38
Next Run on: 04/15/2018 12:07:38
Next Run on: 04/22/2018 12:07:38
Next Run on: 04/29/2018 12:07:38
Next Run on: 05/06/2018 12:07:38
Next Run on: 05/13/2018 12:07:38
Next Run on: 05/20/2018 12:07:38

PL/SQL procedure successfully completed.



Rating

  (8 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Wrong focus

Peter Nosko, October 21, 2017 - 5:54 pm UTC

I think I threw you off tangent by even mentioning history. I'm not interested in the job history; our jobs maintain an application table for that purpose. My bad. Let me try again.

I have a job scheduled to run weekly. It has been running fine for months. All of a sudden, I have a need to skip a week. Or maybe I just want to tweak the time.
JOB_NAME                       REPEAT_INTERVAL           START_DATE           LAST_START_DATE      NEXT_RUN_DATE     
------------------------------ ------------------------- -------------------- -------------------- --------------------
ADJ_CUTOFF_SWEEP               FREQ=WEEKLY;INTERVAL=1    2017-10-12 02:00:00  2017-10-19 02:00:01  2017-10-26 02:00:00

I want the job to now run at 3AM instead. Is there a way to change that NEXT_RUN_DATE without dropping and recreating the job?
Connor McDonald
October 22, 2017 - 9:26 am UTC

In that case, its trivial - you just change set an attribute

SQL> create table t ( x timestamp);

Table created.

SQL> create or replace procedure logger is
  2  begin
  3    insert into t values (localtimestamp);
  4    commit;
  5  end;
  6  /

Procedure created.

SQL> begin
  2    dbms_scheduler.create_job (
  3      job_name        => 'my_job',
  4      job_type        => 'plsql_block',
  5      job_action      => 'begin logger; end;',
  6      start_date      => systimestamp,
  7      repeat_interval => 'freq=minutely; bysecond=0;',
  8      enabled         => true);
  9  end;
 10  /

PL/SQL procedure successfully completed.

SQL>
SQL> select * from t;

X
------------------------------------------------------------
22-OCT-17 05.16.00.364000 PM
22-OCT-17 05.15.00.510000 PM

SQL> begin
  2        dbms_scheduler.set_attribute (
  3          name      => 'my_job',
  4          attribute => 'start_date',
  5          value     => sysdate+300/86400);
  6  end;
  7  /

PL/SQL procedure successfully completed.

SQL> select * from t;

X
-------------------------------------
22-OCT-17 05.16.00.364000 PM
22-OCT-17 05.17.00.382000 PM
22-OCT-17 05.23.00.061000 PM
22-OCT-17 05.24.00.202000 PM
22-OCT-17 05.25.00.396000 PM
22-OCT-17 05.15.00.510000 PM

6 rows selected.



The solution was not obvious

Peter Nosko, October 23, 2017 - 6:40 pm UTC

Connor, thank you for making me look a little harder at a solution I had tried, but didn't give enough time. The Oracle documentation on setting the START_TIME says "The original date and time on which this job started or is scheduled to start." The term "original" did not give me a warm fuzzy that altering it after the job had started running on schedule would have any affect, so I did not notice that altering it also causes the NEXT_RUN_DATE to be updated. Thanks again.
Connor McDonald
October 24, 2017 - 1:06 am UTC

Glad we could help.

One final point

Peter Nosko, October 24, 2017 - 3:20 pm UTC

When the START_DATE is modified, the NEXT_RUN_DATE is only updated if/when the job is/becomes ENABLED. This is probably why I thought my earlier tests were not working. I had disabled the job while deciding when to reschedule the next execution.

The example works but ...

Pedro, June 07, 2018 - 8:12 pm UTC

Connor,

Your last example works.
How about instead of the start_date being larger that the frequency we make the start_date smaller than frequency:
create table t ( x timestamp);
create or replace procedure logger is
begin
insert into t values (localtimestamp);
commit;
end;
/
TRUNCATE TABLE T;
begin
dbms_scheduler.create_job (
job_name => 'my_job',
job_type => 'plsql_block',
job_action => 'begin logger; end;',
start_date => systimestamp,
-- repeat_interval => 'freq=minutely; bysecond=0;',
repeat_interval => 'freq=daily; bysecond=0;',
enabled => true);
end;
/
begin
dbms_scheduler.set_attribute (
name => 'my_job',
attribute => 'start_date',
value => sysdate+300/86400);
end;
/
... and nothing happens.
How does one make the job to execute right away and than stick to the predefined frequency schedule (just like your example did)
Thank you,

Pedro
Connor McDonald
June 08, 2018 - 7:07 am UTC

begin 
dbms_scheduler.set_attribute ( 
name => 'my_job', 
attribute => 'start_date', 
value => sysdate+300/86400); 
end; 
/ 
... and nothing happens. 


I would expect nothing to happen for 5 minutes...if you want it to start now, then start_date would be sysdate

Table T not populated

Peter, June 12, 2018 - 1:19 pm UTC

Connor,

Thank you for the quick response and apologize for the delay.
I executed:
begin
dbms_scheduler.set_attribute (
name => 'my_job',
attribute => 'start_date',
value => sysdate);
end;
/
the start_date and next_run_date in dba_scheduler_jobs changed, last_start_date remains NULL, procedure logger never executed, table t is empty.
Where do we go from here?
Thank you,

Peter
Connor McDonald
June 13, 2018 - 2:12 am UTC

Hmmm... can I get a top to bottom test case ? I'm not seeing that unless I fiddle with enabled, eg

SQL> create table t ( x timestamp);

Table created.

SQL>
SQL> create or replace procedure logger is
  2      begin
  3        insert into t values (localtimestamp);
  4        commit;
  5      end;
  6  /

Procedure created.

SQL>
SQL> begin
  2        dbms_scheduler.create_job (
  3          job_name        => 'my_job',
  4          job_type        => 'plsql_block',
  5          job_action      => 'begin logger; end;',
  6          start_date      => systimestamp,
  7          repeat_interval => 'freq=minutely; bysecond=0;',
  8          enabled         => false);
  9      end;
 10  /

PL/SQL procedure successfully completed.

--
-- nothing because not enabled
--
SQL>
SQL> select * from t;

no rows selected

SQL>
SQL> begin
  2    dbms_scheduler.set_attribute (
  3      name      => 'my_job',
  4      attribute => 'start_date',
  5      value     => sysdate);
  6  end;
  7  /

PL/SQL procedure successfully completed.

--
-- still nothing because not enabled
--

SQL>
SQL> select * from t;

no rows selected

SQL> select * from t;

no rows selected

--
-- I enable
--

SQL> exec dbms_scheduler.enable('my_job');

PL/SQL procedure successfully completed.

SQL> select sysdate from dual;

SYSDATE
-------------------
13/06/2018 10:10:02

1 row selected.

--
-- Nothing (briefly) whilst the scheduler kicks into gear
--

SQL> select * from t;

no rows selected

--
-- and then we're good
--

SQL> /

X
---------------------------------------------------------------------------
13-JUN-18 10.10.02.708000 AM

1 row selected.

SQL>


REPEAT_INTERVAL 'freq=daily; bysecond=0;' is the difference

Peter, June 13, 2018 - 2:04 pm UTC

Connor,

Underneath is the top to bottom test case. The only difference between yours and mine is in dbms_scheduler.create_job, you have repeat_interval => 'freq=minutely; bysecond=0;', and I have repeat_interval => 'freq=daily; bysecond=0;'. With repeat_interval => 'freq=daily; bysecond=0;' the test case does not populate table t after executing dbms_scheduler.set_attribute value => SYSDATE.

create table t ( x timestamp);
create or replace procedure logger is
begin
insert into t values (localtimestamp);
commit;
end;
/
TRUNCATE TABLE T;
begin
dbms_scheduler.create_job (
job_name => 'my_job',
job_type => 'plsql_block',
job_action => 'begin logger; end;',
start_date => systimestamp,
--Connor-- repeat_interval => 'freq=minutely; bysecond=0;',
repeat_interval => 'freq=daily; bysecond=0;',
enabled => true);
end;
/
begin
dbms_scheduler.set_attribute (
name => 'my_job',
attribute => 'start_date',
value => sysdate);
end;
/
Thank you,

Peter
Connor McDonald
June 14, 2018 - 2:18 am UTC

It is your "bysecond" parameter. We're going to run this on second 00, and if not, then we'll wait until tomorrow and do it then.

Example 1, submitted at any old time

SQL> create table t ( x timestamp);

Table created.

SQL> create or replace procedure logger is
  2  begin
  3  insert into t values (localtimestamp);
  4  commit;
  5  end;
  6  /

Procedure created.

SQL> TRUNCATE TABLE T;

Table truncated.

SQL> begin
  2
  3  dbms_scheduler.create_job (
  4  job_name => 'my_job',
  5  job_type => 'plsql_block',
  6  job_action => 'begin logger; end;',
  7  start_date => systimestamp,
  8  repeat_interval => 'freq=daily; bysecond=0;',
  9  enabled => true);
 10  end;
 11  /

PL/SQL procedure successfully completed.

SQL> select sysdate, count(*), max(x) from t;

SYSDATE               COUNT(*) MAX(X)
------------------- ---------- ----------------------------------
14/06/2018 10:15:52          0

SQL>
SQL> /

SYSDATE               COUNT(*) MAX(X)
------------------- ---------- ----------------------------------
14/06/2018 10:15:56          0

SQL> /

SYSDATE               COUNT(*) MAX(X)
------------------- ---------- ----------------------------------
14/06/2018 10:15:59          0

SQL> /

SYSDATE               COUNT(*) MAX(X)
------------------- ---------- ----------------------------------
14/06/2018 10:15:59          0

SQL> /

SYSDATE               COUNT(*) MAX(X)
------------------- ---------- ----------------------------------
14/06/2018 10:16:03          0

SQL> /

SYSDATE               COUNT(*) MAX(X)
------------------- ---------- ----------------------------------
14/06/2018 10:16:04          0


Example 2 - submitted on second 00

SQL> create table t ( x timestamp);

Table created.

SQL> create or replace procedure logger is
  2  begin
  3  insert into t values (localtimestamp);
  4  commit;
  5  end;
  6  /

Procedure created.

SQL> TRUNCATE TABLE T;

Table truncated.

SQL> begin
  2  while to_char(sysdate,'SS')!= '00' loop   --| 
  3    dbms_lock.sleep(0.1);                   --|
  4  end loop;                                 --|
  5  dbms_scheduler.create_job (
  6  job_name => 'my_job',
  7  job_type => 'plsql_block',
  8  job_action => 'begin logger; end;',
  9  start_date => systimestamp,
 10  repeat_interval => 'freq=daily; bysecond=0;',
 11  enabled => true);
 12  end;
 13  /

PL/SQL procedure successfully completed.

SQL> select sysdate, count(*), max(x) from t;

SYSDATE               COUNT(*) MAX(X)
------------------- ---------- -------------------------------------
14/06/2018 10:17:00          0

SQL> /

SYSDATE               COUNT(*) MAX(X)
------------------- ---------- -------------------------------------
14/06/2018 10:17:03          1 14-JUN-18 10.17.00.133000 AM


Typically I'd imagine you would want to be more specific on your interval, ie, "I want to run to at 1pm each day" etc.

My bad malforming the problem

Peter, June 14, 2018 - 8:53 pm UTC

Connor,

Thank you very much for explaining in details why the repeat_interval => 'freq=daily; bysecond=0;' won't work. I apologize but I malformed my problem. Underneath is the sample case, again the only difference between yours and mine is the repeat_interval in dbms_scheduler.create_job. The job will be executed by the scheduler on MON,TUE,WED,THU,FRI,SAT; at 1:00. How could one execute the job 1 time now (SYSDATE) without affecting the above schedule?
create table t ( x timestamp);
create or replace procedure logger is
begin
insert into t values (localtimestamp);
commit;
end;
/
TRUNCATE TABLE T;
begin
dbms_scheduler.create_job (
job_name => 'my_job',
job_type => 'plsql_block',
job_action => 'begin logger; end;',
start_date => systimestamp,
-- repeat_interval => 'freq=minutely; bysecond=0;',
-- repeat_interval => 'freq=daily; bysecond=0;',
repeat_interval => 'FREQ=WEEKLY; BYDAY=MON,TUE,WED,THU,FRI,SAT; BYHOUR=1; BYMINUTE=0',
enabled => true);
end;
/
Thank you,

Peter

Connor McDonald
June 15, 2018 - 1:13 am UTC

dbms_scheduler.run_job ?

One word answer

Peter, June 15, 2018 - 2:33 pm UTC

Yes, yes and yes... it works. Not in vain you manage asktom.com where men go when there is no hope. Apologize for the misguided test case and thank you very much.
Connor McDonald
June 16, 2018 - 1:20 am UTC

:-)

More to Explore

Scheduler

All of the database utilities including the Scheduler are explained in the Utilities guide.