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.
Related
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.
Create a resource, and limit jobs to 1
begin dbms_scheduler.create_resource(resource_name=>'SO_TEST_RESOURCE',units=>'1'); END;
While I can create a job, assign a resource, and even a priority, the subsequent jobs (assigned to the same resource and various priorities) that are queued, are run in random order not FIFO, and not in priority order. Looking for a way to force the next job queued (assigned to that same resource) to be the one that runs next.
DBMS_SCHEDULER.create_job (
job_name => 'SO_JOB1_TEST_RESOURCE',
job_type => 'PLSQL_BLOCK',
job_action => 'begin DBMS_SESSION.sleep(40); end;',
auto_drop => true,
start_date => systimestamp,
enabled => false);
DBMS_SCHEDULER.set_resource_constraint (
object_name => 'SO_JOB1_TEST_RESOURCE',
resource_name => 'SO_TEST_RESOURCE',
units => 1);
DBMS_SCHEDULER.SET_ATTRIBUTE(
NAME => 'SO_JOB1_TEST_RESOURCE',
ATTRIBUTE => 'job_priority',
VALUE =>1 );
DBMS_SCHEDULER.enable('SO_JOB1_TEST_RESOURCE');
.... adding more jobs 2, 3, 4 run in random order
Oracle DBMS_SCHEUDLER CHAINS is probably what you are looking for. You can create a chain first
BEGIN
DBMS_SCHEDULER.CREATE_CHAIN (
chain_name => 'my_chain1',
rule_set_name => NULL,
evaluation_interval => NULL,
comments => 'My first chain');
END;
/
... and then add each scheduled job into the chain as steps in the chain.
BEGIN
DBMS_SCHEDULER.DEFINE_CHAIN_STEP (
chain_name => 'my_chain1',
step_name => 'my_step1',
program_name => 'my_program1');
DBMS_SCHEDULER.DEFINE_CHAIN_STEP (
chain_name => 'my_chain1',
step_name => 'my_step2',
program_name => 'my_chain2');
END;
/
There is a lot more that can be done with job CHAINS, like checking status, implementing restart logic etc. Oracle Documentation will be good reference.
I am trying to create oracle scheduler job (send mail) by pl/sql process (job is created on button click). It create job successfully but job always finish with error:
"ORA-20001: Security Group ID (your workspace identity) is invalid. ORA-06512: at "APEX_050100.WWV_FLOW_SECURITY", line 2939 ORA-06512: at
"APEX_050100.HTMLDB_UTIL", line 3014 ORA-06512: at line 7 ORA-06512:
at line 7.
I also have tried to set security_group_id directly (apex_util.set_security_group_id(p_security_group_id => my_worspace_id or
wwv_flow_api.set_security_group_id(p_security_group_id=>my_worspace_id) but it always finish with the same error as my sample code. When i try to create job manually in sql developer it works. But when job is created by pl/sql process it finish with the mentioned error. Job is created successfully in both cases (pl/sql process or manually) with the same parameters so i do not understand why in case when job is created by pl/sql process it finish with error.
BEGIN
DBMS_SCHEDULER.CREATE_JOB (
job_name => '"INVERTORY"."TEST"',
job_type => 'PLSQL_BLOCK',
job_action => 'begin
for c1 in (
select workspace_id
from apex_applications
where application_id = 104 )
loop
apex_util.set_security_group_id(p_security_group_id =>
c1.workspace_id);
end loop;
HTMLDB_MAIL.SEND(
p_to => ''****.****#****.com'',
p_from => ''noreply#****.com'',
p_subj => ''test mail'',
p_body => ''komu'');
end;',
number_of_arguments => 0,
start_date => TO_TIMESTAMP_TZ('2017-08-28 10:29:57.000000000 EUROPE/PRAGUE','YYYY-MM-DD HH24:MI:SS.FF TZR'),
repeat_interval => NULL,
end_date => NULL,
enabled => TRUE,
auto_drop => FALSE,
comments => '');
DBMS_SCHEDULER.SET_ATTRIBUTE(
name => '"INVERTORY"."TEST"',
attribute => 'logging_level', value => DBMS_SCHEDULER.LOGGING_OFF);
DBMS_SCHEDULER.enable(
name => '"INVERTORY"."TEST"');
END;
Try changing this :
for c1 in (
select workspace_id
from apex_applications
where application_id = 104 )
loop
apex_util.set_security_group_id(p_security_group_id =>
c1.workspace_id);
end loop;
To this :
SELECT MAX(workspace_id)
INTO v_workspace FROM apex_applications
WHERE application_id = 104;
--set workspace - declare v_workspace above as type number
wwv_flow_api.set_security_group_id(v_workspace)
In any event, it would be better to put your logic in a package in the database and create a job with job_type => 'STORED_PROCEDURE' and call on your procedure from there.
I want to repeate a Job every 5 minutes. I have a test table that I fill with random dates. If there are dates older then SYSDATE-5, than I want to delete them. The following code works only the first time I start the scheduler and it never repeats the job_action agaian:
BEGIN
SYS.DBMS_SCHEDULER.CREATE_JOB (
job_name => '"AUTHMGR"."Test2"',
job_type => 'PLSQL_BLOCK',
job_action => 'BEGIN DELETE FROM TEST WHERE TESTDATE < SYSDATE-5;END;',
number_of_arguments => 0,
start_date => SYSDATE,
repeat_interval => 'FREQ=MINUTELY;INTERVAL=5',
end_date => NULL,
job_class => '"SYS"."DEFAULT_JOB_CLASS"',
enabled => TRUE,
auto_drop => FALSE,
comments => 'Test');
END;
/
Do I use the repeat_interval with wrong FREQ and wrong INTERVAL?
I use the Scheduler in Oracle SQL Developer.
The problem was with the INSERT statements. There was no COMMIT after INSERT.
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;