Modify DBMS_SCHEDULER job to stop running between certain hours and minutes - sql

I need to alter a job to run between 23:00PM up till 19:45PM. I have tried the below which achieves this, but the problem with the below is that the job will always stop for 15minutes per hour, between for example 10:45 till 11:00 etc. I'm not sure if I can modify the below to solve this issue.
BEGIN
DBMS_SCHEDULER.SET_ATTRIBUTE (
name => 'MY_TEST_JOB',
attribute => 'repeat_interval',
value => 'FREQ=SECONDLY;INTERVAL=5;
BYHOUR=23,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19;
BYDAY=mon,tue,wed,thu,fri,sat,sun;
BYMINUTE=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40'
);
END;

Create two schedules and combine them:
exec DBMS_SCHEDULER.CREATE_SCHEDULE('JOB_PERIOD_1',
repeat_interval => 'FREQ=SECONDLY;INTERVAL=5;BYHOUR=23,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18');
exec DBMS_SCHEDULER.CREATE_SCHEDULE('JOB_PERIOD_2',
repeat_interval => 'FREQ=SECONDLY;INTERVAL=5;BYHOUR=19;BYMINUTE=0,1,2,3,4,5,[...],43,44');
BEGIN
DBMS_SCHEDULER.SET_ATTRIBUTE (
name => 'MY_TEST_JOB',
attribute => 'repeat_interval',
value => 'JOB_PERIOD_1,JOB_PERIOD_2'
);
END;
Actually I tested it only with this PL/SQL block.
DECLARE
next_run_date TIMESTAMP := TIMESTAMP '2018-02-06 19:44:00';
res INTEGER := 0;
BEGIN
FOR i IN 1..30 LOOP
DBMS_SCHEDULER.EVALUATE_CALENDAR_STRING('JOB_PERIOD_1,JOB_PERIOD_2', NULL, next_run_date, next_run_date);
DBMS_OUTPUT.PUT_LINE(next_run_date);
END LOOP;
END;

Related

scheduled job's job action exceeds 4000 characters in oracle

I have a scheduled job that I am trying to update its job_action based on new requirements but the string now exceeds 4000 characters. Is there a way to allow the job_action to exceed 4000 characters without problems? Or what's the solution?
You must have scheduler with job_type as PLSQL_BLOCK, which allows 4000 characters in job_action.
If you want more than 4000 characters of code to execute in job than create the procedure with your code (which is more than 4000 characters) and then you need to alter the scheduler with job_type as STORED_PROCEDURE and job_action as your newly created procedure name.
Something like following(example from oracle docs):
BEGIN
DBMS_SCHEDULER.CREATE_JOB (
job_name => 'update_sales',
job_type => 'STORED_PROCEDURE', -- change needed here in your case
job_action => 'OPS.SALES_PKG.UPDATE_SALES_SUMMARY', -- change needed here in your case
start_date => '28-APR-08 07.00.00 PM Australia/Sydney',
repeat_interval => 'FREQ=DAILY;INTERVAL=2', /* every other day */
end_date => '20-NOV-08 07.00.00 PM Australia/Sydney',
auto_drop => FALSE,
job_class => 'batch_update_jobs',
comments => 'My new job');
END;
/
Cheers!!

Virtual Private Database policy predicate has error

I'm trying to implement a vpd. So far I have created a function:
> CREATE OR REPLACE FUNCTION sales_select(
schema_var IN VARCHAR2,
table_var IN VARCHAR2
)
RETURN VARCHAR2
IS
return_val VARCHAR2(400);
BEGIN
return_val := 'time_id >= "01-JAN-01"';
RETURN return_val;
END sales_select;
/
and the policy I made is the following:
L> BEGIN
2 DBMS_RLS.ADD_POLICY (
3 object_schema => 'sh',
4 object_name => 'costs1',
5 policy_name => 'costs_policy',
6 function_schema => 'policy_admin',
7 policy_function => 'sales_select',
8 statement_types => 'select'
9 );
0 END;
1 /
when I run the follow query:
select * from sh.costs1;
I get the following error:
ERROR at line 1:
ORA-28113: policy predicate has error
I'm thinking it has something to do with the quotes in the function but when I try changing them I get compile errors.
Is time_id a date column? If so, try changing line 9 to:
return_val := 'time_id >= date ''2001-01-01''';
Note the double quotes.

Oracle dbms_scheduler.create_job Error

I am trying to create a simple scheduled event in an oracle 10g database. I have been trying to use dbms_scheduler.create_job. Here is the script I wrote:
begin dbms_scheduler.create_job (
job_name => 'disengagementChecker',
job_type => 'PLSQL_BLOCK',
job_action => 'INSERT INTO
PatientClassRelObs(patientClassID,observationTypeID) VALUES (1, 11)',
start_date => SYSDATE,
repeat_interval => 'FREQ=MINUTELY;INTERVAL=1',
comments => 'Iam tesing scheduler'); end;
When I run this, oracle throws these errors
ORA-06550: line 15, column 3:
PLS-00103: Encountered the symbol
"end-of-file" when expecting one of the following:
; The symbol
";" was substituted for "end-of-file" to continue.
I don't understand whats causes this error. Do you know what causes this error? Or why this is happening?
Thank you in advance!
-David
JOB_ACTION must be a valid PL/SQL block, not just a valid SQL statement. Use this:
job_action => '
BEGIN
INSERT INTO PatientClassRelObs(patientClassID,observationTypeID)
VALUES (1, 11);
END;',
UPDATE
Maybe this is a problem with a specific environment or some code not posted. To troubleshoot, start with something that's known to work, and add one small change at a time until something breaks.
Start with this code, using SQL*Plus.
SQL> begin
2 dbms_scheduler.create_job(
3 job_name => 'TEST_JOB',
4 job_type => 'PLSQL_BLOCK',
5 job_action => 'BEGIN NULL; END;',
6 start_date => systimestamp,
7 enabled => true);
8 end;
9 /
PL/SQL procedure successfully completed.
SQL> select status, log_date from dba_scheduler_job_run_details where job_name = 'TEST_JOB';
STATUS LOG_DATE
------------------------------ ---------------------------------------------------------------------------
SUCCEEDED 26-MAR-14 11.37.59.533000 PM -05:00

Job scheduling is not working in oracle

Created job like below :
BEGIN
Dbms_Scheduler.create_job(
job_name => 'PROECSS_STATE'
,job_type => 'STORED_PROCEDURE'
,job_action => 'ARCHIVE_AND_DELETE' -- Procedure Name
,start_date => SYSDATE
,repeat_interval => 'freq=DAILY; byhour=13' --Added byhour
,enabled => TRUE
,comments => 'job schedule for archiving process_state');
END;
When i created the job, the time was "21-mrt-2014 12:55:55"
But nothing has happened after checking( Checked at 13:05:45).
Procedure did not run as expected.
Can any one please tell me why job has not been executed?
Replace start_date => SYSDATE with start_date => SYSTIMESTAMP.
This is only a problem on some problems. For example, the code below runs 2 jobs on Oracle 12c on Windows, but only runs the first job on 11gR2 on Solaris.
begin
dbms_scheduler.create_job('TEST_JOB1', 'PLSQL_BLOCK', 'begin null; end;'
,start_date => systimestamp, enabled => true);
dbms_scheduler.create_job('TEST_JOB2', 'PLSQL_BLOCK', 'begin null; end;'
,start_date => sysdate , enabled => true);
end;
/
--Only one job ran (on some platforms).
select * from dba_scheduler_job_run_details where job_name like 'TEST%';
I do not know why this happens. I would appreciate it if anyone could explain it.

Have PL/SQL Outputs in Real Time

Is it possible to have Outputs from PL/SQL in real time? I have a pretty huge package that runs for more than an hour and I'd like to see where the package is at a particular time.
Anyways, I currently do this with a log table, which gets filled up with hundreds of log descriptions per run, I'm just curious if this is possible.
Thanks!
This is the kind of thing I use (output can be seen in v$session and v$session_longops)...
DECLARE
lv_module_name VARCHAR2(48);
lv_action_name VARCHAR2(32);
gc_MODULE CONSTANT VARCHAR2(48) := 'MY_PROC';
-- For LONGOPS
lv_rindex BINARY_INTEGER;
lv_slno BINARY_INTEGER;
lc_OP_NAME CONSTANT VARCHAR2(64) := '['||gc_MODULE||']';
lv_sofar NUMBER;
-- This is a guess as to the amount of work we will do
lv_totalwork NUMBER;
lc_TARGET_DESC CONSTANT VARCHAR2(64) := 'Tables';
lc_UNITS CONSTANT VARCHAR2(64) := 'Rows';
CURSOR tab_cur
IS
SELECT owner, table_name
FROM all_tables;
BEGIN
<<initialisation>>
BEGIN
-- To preserve the calling stack, read the current module and action
DBMS_APPLICATION_INFO.READ_MODULE( module_name => lv_module_name
, action_name => lv_action_name );
-- Set our current module and action
DBMS_APPLICATION_INFO.SET_MODULE( module_name => gc_MODULE
, action_name => NULL );
END initialisation;
<<main>>
BEGIN
DBMS_APPLICATION_INFO.SET_ACTION( action_name => 'Part 01' );
NULL;
DBMS_APPLICATION_INFO.SET_ACTION( action_name => 'Part 02' );
FOR tab_rec IN tab_cur
LOOP
DBMS_APPLICATION_INFO.SET_CLIENT_INFO( client_info => 'Rows = ['||TO_CHAR( tab_cur%ROWCOUNT, '999,999,999' )||']' );
NULL;
END LOOP;
DBMS_APPLICATION_INFO.SET_ACTION( action_name => 'Part 03' );
--Initialising longops
lv_rindex := DBMS_APPLICATION_INFO.SET_SESSION_LONGOPS_NOHINT;
lv_sofar := 0;
lv_totalwork := 5000; -- This is a guess, but could be actual if the query is quick
FOR tab_rec IN tab_cur
LOOP
DBMS_APPLICATION_INFO.SET_CLIENT_INFO( client_info => 'Rows = ['||TO_CHAR( tab_cur%ROWCOUNT, '999,999,999' )||']' );
lv_sofar := lv_sofar + 1;
-- Update our totalwork guess
IF lv_sofar > lv_totalwork
THEN
lv_totalwork := lv_totalwork + 500;
END IF;
DBMS_APPLICATION_INFO.SET_SESSION_LONGOPS( rindex => lv_rindex
, slno => lv_slno
, op_name => lc_OP_NAME
, sofar => lv_sofar
, totalwork => lv_totalwork
, target_desc => lc_TARGET_DESC
, units => lc_UNITS
);
END LOOP;
-- Clean up longops
DBMS_APPLICATION_INFO.SET_SESSION_LONGOPS( rindex => lv_rindex
, slno => lv_slno
, op_name => lc_OP_NAME
, sofar => lv_sofar
, totalwork => lv_sofar
, target_desc => lc_TARGET_DESC
, units => lc_UNITS
);
END main;
<<finalisation>>
BEGIN
-- Reset the module and action to the values that may have called us
DBMS_APPLICATION_INFO.SET_MODULE( module_name => lv_module_name
, action_name => lv_action_name );
-- Clear the client info, preventing any inter process confusion for anyone looking at it
DBMS_APPLICATION_INFO.SET_CLIENT_INFO( client_info => NULL );
END finalisation;
END;
/
I don't know if this is exactly what you want but I use dbms_application_info.set_module to see where my package is.
dbms_application_info.set_module(module_name => 'Conversion job',
action_name => 'updating table_x');
A query on v$session will show you which part of the procedure is running.
you could use autonomous transactions (as suggested in this SO for example).
This would allow you to write and commit in a log table without commiting the main transaction. You would then be able to follow what happens in your main script while it is running (incidentally, it will also allow you to time/tune your batch).
Use DBMS_PIPE to write a message to a named pipe. In another session you can read the messages from the pipe. Very simple, works like a charm !
procedure sendmessage(p_pipename varchar2
,p_message varchar2) is
s number(15);
begin
begin
sys.dbms_pipe.pack_message(p_message);
exception
when others then
sys.dbms_pipe.reset_buffer;
end;
s := sys.dbms_pipe.send_message(p_pipename, 0);
if s = 1
then
sys.dbms_pipe.purge(p_pipename);
end if;
end;
function receivemessage(p_pipename varchar2
,p_timeout integer) return varchar2 is
n number(15);
chr varchar2(200);
begin
n := sys.dbms_pipe.receive_message(p_pipename, p_timeout);
if n = 1
then
return null;
end if;
sys.dbms_pipe.unpack_message(chr);
return(chr);
end;
If your long-running job is processing a large number of fairly evenly sized tasks, you may find session longops a good way of monitoring the job progress, as well as allowing you to estimate how long the job will take to finish.
DBMS_APPLICATION_INFO.set_session_longops
If you have access to shell from PL/SQL environment you can call netcat:
BEGIN RUN_SHELL('echo "'||v_msg||'" | nc '||v_host||' '||v_port||' -w 5'); END;
/
v_host is a host running python script that reads data from socket on port v_port.
I used this design when I wrote aplogr for shell and pl/sql logs monitoring.