How to schedule one time executable job in Oracle? - oracle

I want to schedule a job that will execute only once; example on 01/01/2023 00:00:00. It should not repeat again. This job will call a program with a stored procedure that will update some tables.
I have written the below code by referring the answers of this question. It is not working when I set the end_date as the same date with different time. Is repeat_interval mandatory?
-- Procedure
CREATE OR REPLACE PROCEDURE P_INSURANCE_DEACTIVATION
IS
BEGIN
UPDATE SCHEME SET SCC_STATUS = 'N', US_CODE = 'D001' WHERE SC_CODE = 'N013';
UPDATE INSURANCE SET INC_STATUS = 'N', US_CODE = 'D001' WHERE IN_CODE = 'N007';
COMMIT;
END;
-- Schedule
BEGIN
DBMS_SCHEDULER.CREATE_SCHEDULE (
schedule_name => 'SCH_INSURANCE_DEACT',
start_date => TO_DATE('22-12-2022 18:05:00','DD-MM-YYYY HH24:MI:SS'),
repeat_interval => 'FREQ=MINUTELY; INTERVAL=1; ',
end_date => TO_DATE('22-12-2022 18:07:00','DD-MM-YYYY HH24:MI:SS'),
comments => 'Only once');
END;
-- Scheduled Program
BEGIN
DBMS_SCHEDULER.CREATE_PROGRAM (
program_name => 'PROG_INSURANCE_DEACT',
program_action => 'P_INSURANCE_DEACTIVATION',
program_type => 'STORED_PROCEDURE');
END;
-- Scheduled Job
BEGIN
DBMS_SCHEDULER.CREATE_JOB (
job_name => 'JOB_INSURANCE_DEACT',
program_name => 'PROG_INSURANCE_DEACT',
schedule_name => 'SCH_INSURANCE_DEACT');
END;
exec dbms_scheduler.enable('JOB_INSURANCE_DEACT’)

After looking at the documentation for DBMS_SCHEDULER, you can see that you can create a scheduled job without needing to define a schedule as long as you set a start time.
Personally, I wouldn't bother creating a procedure and program since the code being executed is so simple and it is just a one-time job.
The code below can be used to create a job that will run at midnight on Jan 1st 2023, but you might need to adjust the time zone for your scenario since midnight is at a different time depending which time zone you are in.
BEGIN
DBMS_SCHEDULER.create_job (job_name => 'JOB_INSURANCE_DEACT',
job_type => 'PLSQL_BLOCK',
job_action => q'[BEGIN
UPDATE SCHEME SET SCC_STATUS = 'N', US_CODE = 'D001' WHERE SC_CODE = 'N013';
UPDATE INSURANCE SET INC_STATUS = 'N', US_CODE = 'D001' WHERE IN_CODE = 'N007';
COMMIT;
END;]',
start_date => TIMESTAMP '2023-01-01 00:00:00 -05:00',
enabled => TRUE);
END;
As an additional note, you do not need to have a COMMIT at the end of your code being executed by a job. When a job completes, it will automatically commit.

Related

Can not Run Completed Oracle Job again

Can not run a completed DBMS_SCHEDULER job by remove the END_DATE
Hello, everyone!
I am using oracle 12cR1,now I have a problem in DBMS_SCHEDULER jobs.
First, I created an repeated oracle DBMS_SCHEDULER jobs with END_DATE was set,
after the set END_DATE, the job completed successfully, and the enabled state of job changed to disabled automatically.
According to the running log of the job, the Operation was COMPLETED, while Additional info was REASON="End time reached"
That was expected.
Then I wanted to run the job again, I removed the END_DATE field by
SYS.DBMS_SCHEDULER.SET_ATTRIBUTE('JOB_XXX', 'END_DATE', '');
and set the job enable by
SYS.DBMS_SCHEDULER.ENABLE(name => 'JOB_XXX');
I can see the job was enabled again and END_DATE was empty.
But The Job run again only once, and stopped, the running log of was COMPLETED, while Additional info was REASON="End time reached" again.
BEGIN
sys.dbms_scheduler.CREATE_JOB(
JOB_NAME => 'JOB_3358',
job_type => 'STORED_PROCEDURE',
JOB_ACTION => 'TEST_JOB',
START_DATE => to_date('2019-05-05 13:35:00','yyyy-mm-dd hh24:mi:ss'),
REPEAT_INTERVAL => 'FREQ= SECONDLY;INTERVAL=30',
END_DATE => to_date('2019-05-05 13:38:00','yyyy-mm-dd hh24:mi:ss'),
auto_drop => FALSE,
COMMENTS => NULL);
END;
/
begin
sys.dbms_scheduler.enable(name => 'JOB_3358');
end;
/
What I expected was that the job will run according to REPEAT_INTERVAL again,
and as end_date was empty, it should never stop.
Is there any mistake in removing END_DATE, or is this the oracle's bug?
Thanks in advance, and best Regards!
tricky one. I reproduced your problem. Then, I tried to change start_date to systimestamp when removing end_date, which again did not work. But, then I changed start_date to systimestamp plus a bit when removing end_date, and then it worked. Working example below. It seems some info about the job is cached/stored somewhere and we can remove this info by setting start_date slightly into the future so that scheduling-logic is triggered when enabling the job (my wild theory on what happens). Working example for removing end_date of completed job:
BEGIN
sys.dbms_scheduler.CREATE_JOB(
JOB_NAME => 'MYUSER.JOB_3358',
job_type => 'PLSQL_BLOCK',
JOB_ACTION => 'begin null; end;',
START_DATE => systimestamp,
REPEAT_INTERVAL => 'FREQ= SECONDLY;INTERVAL=30',
END_DATE => systimestamp + interval '2' minute,
auto_drop => FALSE,
COMMENTS => NULL);
END;
/
begin
sys.dbms_scheduler.enable(name => 'MYUSER.JOB_3358');
end;
/
-- wait until job shows as completed
exec DBMS_SCHEDULER.set_attribute_null (name=>'MYUSER.JOB_3358', attribute=>'end_date');
begin
dbms_scheduler.set_attribute (
name => 'MYUSER.JOB_3358',
attribute => 'start_date',
value => systimestamp + interval '1' minute);
end;
/
begin
sys.dbms_scheduler.enable(name => 'MYUSER.JOB_3358');
end;
/
-- job will continue to run every 30 seconds indefinitely
--cleanup
exec sys.dbms_scheduler.drop_JOB( JOB_NAME => 'MYUSER.JOB_3358');
Edit: the above does NOT reliably work. It works sometimes, but not always. The only (silly!!!) approach which reliably worked so far in my tests is:
exec DBMS_SCHEDULER.set_attribute_null (name=>'MYUSER.JOB_3358', attribute=>'end_date');
-- This line raises "ORA-27469: NEXT_RUN_DATE is not a valid job attribute" but is necessary.
exec DBMS_SCHEDULER.set_attribute_null (name=>'MYUSER.JOB_3358', attribute=>'next_run_date');
exec dbms_scheduler.enable(name => 'MYUSER.JOB_3358');

Creating DBMS_SCHEDULER job for oracle

Trying to create job But can't compile it keeps me given this error. There is a question on oracle forums, it say's that i have to create program to wrap it. Is there any workaround for this?
-- Created on 30.09.2014 by ALI.ORHAN
declare
-- Local variables here
i integer;
begin
-- Test statements here
dbms_scheduler.create_job(job_name => 'blabla'
,job_type => 'STORED_PROCEDURE'
,job_action => 'dingdongprocedure;'
,start_date => '30-OCT-14 10.00.00 PM'
,end_date => '15-JULY-08'
,repeat_interval => 'FREQ=WEEKLY BYDAY=TUE,FRI BYHOUR=10,13'
,enable => 'TRUE'
,comments => 'SUPREME COMMENT');
end;
After i created job from PL/SQL Developer UI, i found out my syntax erorrs, new code is below;
i use sys.dbms_scheduler.create_job instead of dbms_scheduler.create_job. I don't know differances but it's not important alteration.
i used to_date to define start_date, as a fresh-starter i found this better practise.
Important I added job_class parameter to 'DBMS_JOB$'. DBMS_JOB is built_in job class of Oracle RDBMS. So you find all jobs with this query:
select * from ALL_SCHEDULER_JOBS WHERE JOB_CLASS='DBMS_JOB$'
Important My interval's were wrong you should put ; between all parameters like
repeat_interval => freq=weekly;byhour=10, 13
My first job code has another syntax error i use enable instead of enabled.
I set auto_drop false. I guess this parameter is used to drop job when it dones his job. I mean if you create a job that makes changes daily from today to next week. After end-time reaches, this job has dropped. Please correct me if i wrong.
sys.dbms_scheduler.create_job(job_name => 'BOMBASTICJOB'
,job_type => 'STORED_PROCEDURE'
,job_action => 'dingdongprocedure'
,start_date => to_date('30-09-2014 00:00:00'
, 'dd-mm-yyyy hh24:mi:ss')
,end_date => to_date(null)
,job_class => 'DBMS_JOB$'
,repeat_interval => 'Freq=Weekly; ByDay=Tue, Fri; ByHour=10, 13'
,enabled => true
,auto_drop => false
,comments => '');
I am on 12.1.0.1.0. You could create the job in a simple anonymous block :
SQL> BEGIN
2 DBMS_SCHEDULER.DROP_JOB (JOB_NAME => 'test_full_job_definition');
3 END;
4 /
PL/SQL procedure successfully completed.
SQL>
SQL> BEGIN
2 DBMS_SCHEDULER.create_job (
3 job_name => 'test_full_job_definition',
4 job_type => 'PLSQL_BLOCK',
5 job_action => 'BEGIN my_job_procedure; END;',
6 start_date => SYSTIMESTAMP,
7 repeat_interval => 'freq=hourly; byminute=0; bysecond=0;',
8 end_date => NULL,
9 enabled => TRUE,
10 comments => 'Job defined entirely by the CREATE JOB procedure.');
11 END;
12 /
PL/SQL procedure successfully completed.
SQL>
SQL> SELECT JOB_NAME, ENABLED FROM DBA_SCHEDULER_JOBS where job_name ='TEST_FULL_JOB_DEFINITION'
2 /
JOB_NAME ENABL
---------------------------------------- -----
TEST_FULL_JOB_DEFINITION TRUE
SQL>
More examples here

DBMS SCHEDULER Job with input

Hi I have a stored procedure in oracle that I would like to run periodically. Firstly I got my DBMS_SCHEDULER Job to compile (see below) and I can even see the job be created and drop it though I don't see the result of the stored procedure occur in the table it is supposed to effect and the stored procedure has been tested.
BEGIN
DBMS_SCHEDULER.CREATE_JOB (
job_name => 'JOB_QUERY',
job_type => 'PLSQL_BLOCK', -- see oracle documentation on types --
job_action => 'BEGIN RUNREPORT(''NAME'', ''VERSION'', ''04-Jun-13'', ''11-Jun-13''); END;',
start_date => to_date('2013-08-19 16:35:00', 'YYYY-MM-DD HH24:MI:SS' ),
repeat_interval => 'FREQ=MINUTELY;BYMINUTE=10', -- every 10 minutes.
end_date => NULL,
enabled => TRUE,
comments => 'Daily Jira Query Update');
END;
I was attempting to simply make it run every ten minutes though I see no changes. Also I wanted to be able to pass SYSDATE or the current date to the procedure in the dbms_scheduler job but I cant get it to work with the apostrophes.
Thanks
You have to COMMIT your DML statements. There is no COMMIT in PL/SQL block and I guess in procedure RUNREPORT either.
You don't need an apostrophe around sysdate, it's not a string literal.
job_action => 'BEGIN RUNREPORT(''NAME'', ''VERSION'', sysdate, ''11-Jun-13''); COMMIT; END;',
BYMINUTE does not mean what you would expect. From documentation:
"This specifies the minute on which the job is to run. Valid values are 0 to 59. As an example, 45 means 45 minutes past the chosen hour". What you need is
repeat_interval => 'FREQ=MINUTELY;INTERVAL=10'
You can check next run date and more by querying user_scheduler_jobs.
If you are calling the stored procedure from DMBS Scheduled job you can try below.
BEGIN
DBMS_SCHEDULER.CREATE_JOB (
JOB_NAME => 'SCHEMA.MY_DBMS_SCHEDULED_JOB',
JOB_TYPE => 'STORED_PROCEDURE',
JOB_ACTION => 'SCHEMA.STORED_PROCEDURE_TO_BE_CALLED',
START_DATE => '01-AUG-13 12.00.00 AM',
REPEAT_INTERVAL => 'FREQ=DAILY;BYHOUR=0;BYMINUTE=10',
AUTO_DROP => FALSE,
ENABLED => TRUE,
NUMBER_OF_ARGUMENTS => 0,
COMMENTS => 'Scheduled job to perform updates.');
END;
/
To see if your scheduler log you can use below query.
SELECT * FROM all_SCHEDULER_JOB_LOG
where job_name='MY_DBMS_SCHEDULED_JOB'
order by log_id desc;

automated alert emails using sql developer

A supermarket has many products. When one of these products reaches a quantity of zero an automated email needs to be sent to the manager, showing that this product is out of stock.
I have done the email part( sending email through SQL Developer ). Now I need to set up a loop to keep tracking the products' quantity. How is this loop called? .
APC? i tried this out. but its not working for me
create or replace
procedure check_stock_qty
begin
for r in ( select product_name,product_id from super_market
where pro_qty = 0 )
loop
UTL_MAIL.send(sender => 'blabla#me.com',
recipients => 'blabla#me.com',
subject => 'Test Mail',
message => ( r.product_name ),
mime_type => 'text; charset=us-ascii');
end loop;
end;
------------------------
BEGIN
dbms_scheduler.create_job (job_name => 'stock check',
job_type => 'PLSQL_BLOCK',
job_action => 'BEGIN check_stock_qty; END;',
start_date => SYSTIMESTAMP,
repeat_interval => 'freq=minutely; interval=5; bysecond=0;',
end_date => NULL,
enabled => TRUE,
END;
the procedure compiled, but win run it. it gives an error " the selected program is in an invalid state for running. recompile the program and try again "
The best way to do this would be to use a database job to periodically check the PRODUCTS table.
First of all you need a stored procedure. Something like this:
create or replace procedure check_stock_qty
begin
for r in ( select product_name from products
where qty = 0 )
loop
your_email_proc_here ( r.product_name );
end loop;
end;
You would then set this to run at regular intervals. As you're using Oracle 11g you should use the DBMS_SCHEDULER API to do this. This calll will run the above stock checker every five minutes:
BEGIN
dbms_scheduler.create_job (
job_name => 'stock check',
job_type => 'PLSQL_BLOCK',
job_action => 'BEGIN check_stock_qty; END;',
start_date => SYSTIMESTAMP,
repeat_interval => 'freq=minutely; interval=5; bysecond=0;',
end_date => NULL,
enabled => TRUE,
END;
/
DBMS_SCHEDULER is pretty sophisticated i.e. complicated but it is well documented. Find out more.

Programming DBA Jobs in Stored procs

I am a little new to programming, so any help is appreciated.
Find below the code of my stored proc to delete a table and also create a DBA job which will run on a hourly basis.
CREATE OR REPLACE procedure DELETE_My_TABLE(myschema varchar2) as
BEGIN
BEGIN
execute immediate 'delete from '||myschema||'.mytable where clause;';
END;
BEGIN
DBMS_SCHEDULER.create_program (
program_name => 'DELETE_My_TABLE',
program_type => 'STORED_PROCEDURE',
program_action => 'execute DELETE_My_TABLE(myschema)',
number_of_arguments => 1,
enabled => FALSE,
comments => 'Program to delete table using a stored procedure.');
DBMS_SCHEDULER.define_program_argument (
program_name => 'DELETE_My_TABLE',
argument_name => 'myschema',
argument_position => 1,
argument_type => 'VARCHAR2',
default_value => 'myschema');
DBMS_SCHEDULER.enable (name => 'DELETE_My_TABLE');
END;
BEGIN
DBMS_SCHEDULER.create_schedule (
schedule_name => 'DELETE_My_TABLE',
start_date => SYSTIMESTAMP,
repeat_interval => 'freq=hourly; byminute=0',
end_date => NULL,
comments => 'Hourly Job to purge SEARCH_TEMP_TABLE');
END;
END;
/
Issues:
ERROR at line 1:
ORA-00920: invalid relational operator
ORA-06512: at "MYSCHEMA.DELETE_My_TABLE", line 4
ORA-06512: at line 1
Will the logic (and syntax) work?
One issue I can see is that you need to take the semi-colon out of the EXECUTE IMMEDIATE string:
execute immediate 'delete from '||myschema||'.mytable where clause';
^^
Removed from here
thought I suspect this won't solve your immediate problem, which looks like it's your BEGIN ...END blocks.
For the Oracle Scheduler you normally create a program, once. Next you create a job that has the program as action. You can give that job a schedule like you specified in your code but you have to choose. Either you create a schedule and have the job use it, or you give the job it's own repeat interval.
I happen to know about a book ( Mastering Oracle Scheduler ) that I wrote that could be very helpful.

Resources