how to create a export table job in oracle 12c - oracle

I want to create a export table job, but I can't understand why its not working.
my table is Department
create table department (id number, name varchar2(200));
I want to export a csv file for per day at 9:00 pm. I need to create it.
I only know:
0. create a directory
create a PROCEDURE
create a DBMS_SCHEDULER.CREATE_PROGRAM
create a DBMS_SCHEDULER.CREATE_SCHEDULE
create a DBMS_SCHEDULER.CREATE_JOB
excute the job
thanks

Yes, you can use DBMS_SCHEDULER by creating in such a way
DECLARE
v_job_name VARCHAR2(32) := 'jb_exp_emp_data';
BEGIN
DBMS_SCHEDULER.CREATE_JOB(job_name => v_job_name,
job_type => 'STORED_PROCEDURE',
job_action => 'exp_emp_data',
start_date => TO_DATE('11-12-2021 21:00:10',
'DD-MM-YYYY HH24:MI:SS'),
repeat_interval => 'FREQ=DAILY; BYHOUR=21;',
auto_drop => false,
comments => 'Exports the content of the department table every day at 9:00PM o''clock ');
DBMS_SCHEDULER.ENABLE(v_job_name);
END;
/
that starts at the time defined by the start_date parameter, then repeats on every upcoming days at 9pm in the future.

I followed the steps below and it was successful ...
Create a directory (path of export file):
CREATE OR REPLACE DIRECTORY CSVDIR AS 'D:\';
Create a procedure:
Create Or Replace Procedure exp_emp_data Is
today varchar2(200);
fileName varchar2(200);
n_file utl_file.file_type;
v_string Varchar2(4000);
Cursor c_emp Is
Select
id, name
From
department;
Begin
select to_char(sysdate,'yyyymmdd','nls_calendar=persian') into today from dual;
fileName := 'empdata' || today || '.csv';
n_file := utl_file.fopen('CSVDIR', fileName, 'w', 4000);
v_string := 'ID, Name';
utl_file.put_line(n_file, v_string);
-- open the cursor and concatenate fields using comma
For cur In c_emp Loop
v_string := cur.id
|| ','
|| cur.name;
-- write each row
utl_file.put_line(n_file, v_string);
End Loop;
-- close the file
utl_file.fclose(n_file);
Exception
When Others Then
-- on error, close the file if open
If utl_file.is_open(n_file) Then
utl_file.fclose(n_file);
End If;
End;
/
-------- Test
Begin
exp_emp_data;
End;
/
Create a program:
BEGIN
DBMS_SCHEDULER.CREATE_PROGRAM (
program_name => 'PROG_EXPORT_TABLE',
program_action => 'exp_emp_data',
program_type => 'STORED_PROCEDURE');
END;
/
Create a job:
BEGIN
DBMS_SCHEDULER.CREATE_JOB (
job_name => 'JOB_EXPORT_TABLE',
job_type => 'STORED_PROCEDURE',
job_action => 'PROG_EXPORT_TABLE',
start_date => '16-nov-2021 11:50:00 pm',
repeat_interval => 'FREQ=DAILY;BYHOUR=23;BYMINUTE=59',
enabled => true
);
END;
/
And enabled it:
exec dbms_scheduler.enable('JOB_EXPORT_TABLE');

Related

unable to call main procedure from wrapper procedure asynchronously

I want to call main procedure from the wrapper procedure. Wrapper procedure I'm able to output with dbms output print line but I'm unable to print within the main proc, looks like the main proc is not called from wrapper procedure. Please help me
Below is the table script
CREATE TABLE ASYNC_SAMPLE_TAB
( attribute1 varchar2(50),
attribute2 varchar2(50)
);
Below is my package specification
CREATE OR REPLACE PACKAGE XX_ASYNC_DEMO_PKG
IS
PROCEDURE MAIN_PROC(
attribute1 IN VARCHAR2,
attribute2 IN VARCHAR2
);
PROCEDURE WRAPPER_MAIN_PROC(
attribute1 IN VARCHAR2,
attribute2 IN VARCHAR2
);
END XX_ASYNC_DEMO_PKG;
Below is my package bofy
CREATE OR REPLACE PACKAGE BODY XX_ASYNC_DEMO_PKG
IS
PROCEDURE WRAPPER_MAIN_PROC(
attribute1 IN VARCHAR2,
attribute2 IN VARCHAR2
)
AS
BEGIN
DBMS_OUTPUT.PUT_LINE('-- START OF WRAPPER PROC---' || SYSTIMESTAMP);
dbms_scheduler.create_job(
job_name => 'ASYNC_MAIN_PROC' || '_' || attribute1,
job_type => 'PLSQL_BLOCK',
job_action => 'BEGIN
MAIN_PROC(''' || attribute1 || ''', ''' || attribute2 || ''');
END;',
start_date => systimestamp ,
auto_drop => true,
enabled => true
);
DBMS_OUTPUT.PUT_LINE('-- END OF WRAPPER PROC---' || SYSTIMESTAMP);
END;
PROCEDURE MAIN_PROC(
attribute1 IN VARCHAR2,
attribute2 IN VARCHAR2
)
AS
sql_stmt VARCHAR2(200);
BEGIN
DBMS_OUTPUT.PUT_LINE('-- START OF MAIN PROC---' || SYSTIMESTAMP);
DBMS_SESSION.sleep(10);
sql_stmt := 'INSERT INTO ASYNC_SAMPLE_TAB VALUES (:1, :2)';
EXECUTE IMMEDIATE sql_stmt USING attribute1, attribute2;
DBMS_OUTPUT.PUT_LINE('-- END OF MAIN PROC---' || SYSTIMESTAMP);
END;
END XX_ASYNC_DEMO_PKG;
Below is the command with which I'm trying to test above solution
exec XX_ASYNC_DEMO_PKG.WRAPPER_MAIN_PROC('Test101_1', 'Test101_2');
As described in the documentation, the main purpose of DBMS_OUTPUT is debug messages to trace execution flow. It's also said there that it doesn't immediately return anything to the caller, but text is placed into the buffer and may be retrieved from there by the caller or the program itself (though, you cannot "get into" any other program flow and get anything from the executing code until the called unit is complete).
Scheduler doesn't retrieve the content of the buffer after it completes the job, so DBMS_OUTPUT.PUT* called inside a background job has no effect and you cannot see any result.
You may use some logging table (with separate logging procedure executed in autonomous transaction not to have an influence or be influenced by the main transaction) or external file and UTL_FILE to send results here. Or use a general table that should be processed by the job and check results after it finishes.
UPD:
Below is a complete setup to demonstrate how to pass parameters to a callable and see its results.
We'll log results into this table:
create table log_table (
ts timestamp,
val number,
job_name varchar2(30)
)
Then this procedure will be used to perform an action:
create or replace procedure proc_insert(
p_val in number,
p_job_name in varchar2
) as
begin
insert into log_table(ts, val, job_name)
values (systimestamp, p_val, p_job_name);
commit;
end;
This procedure will call our action procedure in a background job. We need to specify a number of parameters to override default values in a callable when creating a job. And then use DBMS_SCHEDULER.SET_JOB_[ARGUMENT|ANYDATA]_VALUE depending on the parameter type.
create or replace procedure proc_insert_async(
p_call_id varchar2,
p_val number,
r_job_name out varchar2
) as
l_job_prefix constant varchar2(20) := 'LOG_TABLE_';
l_job_name varchar2(100) := l_job_prefix || p_call_id;
begin
dbms_scheduler.create_job(
job_name => l_job_name,
job_type => 'STORED_PROCEDURE',
/*Callable unit - out API procedure*/
job_action => 'TEST_EAS.PROC_INSERT',
/*Number of args to be passed to the proc*/
number_of_arguments => 2,
/*Run immediately*/
start_date => sysdate,
enabled => false,
auto_drop => true
);
/*Pass parameters to the callable*/
dbms_scheduler.set_job_anydata_value (
job_name => l_job_name,
argument_position => 1,
argument_value => sys.anydata.convertNumber(p_val)
);
dbms_scheduler.set_job_argument_value(
job_name => l_job_name,
argument_position => 2,
argument_value => l_job_name
);
/*Start job*/
dbms_scheduler.enable(
name => l_job_name
);
r_job_name := l_job_name;
end;
Finally, test this in action (sleep is added due to async nature of inserts to wait for results).
declare
l_job_name varchar2(100);
begin
proc_insert_async(
p_call_id => 'test1',
p_val => 1,
r_job_name => l_job_name
);
dbms_output.put_line(l_job_name);
proc_insert_async(
p_call_id => 'test2',
p_val => 10,
r_job_name => l_job_name
);
dbms_output.put_line(l_job_name);
dbms_session.sleep(3);
end;
/
LOG_TABLE_test1
LOG_TABLE_test2
PL/SQL procedure successfully completed.
select *
from log_table
TS
VAL
JOB_NAME
25.11.22 10:52:37,310403000
10
LOG_TABLE_test2
25.11.22 10:52:37,302992000
1
LOG_TABLE_test1

PLS-00103: Encountered the symbol in DBMS_SCHEDULER

Calling the package inside the job gives an Error report -
ORA-06550: line 8, column 5:
PLS-00103: Encountered the symbol "
);
end; : AUXSQLDBIND4: = SqlDevBind1Z_1; : AUXSQLDBIND3: = SqlDevBind1Z_2; : AUXSQLDBIND2: = SqlDevBind1Z_3; : AUXSQLDBIND1: = SqlDevBind "
Help call the packet with the passed variable work_date for a certain calculation for each day of the month.
Thanks in advance for your help!
DBMS_SCHEDULER.create_job (
job_name => 'J_ACCOUNT_TURNOVER_F',
job_type => 'PLSQL_BLOCK',
start_date => SYSTIMESTAMP, enabled => TRUE,
job_action =>
'declare
start_date number;
end_date number;
work_date date;
begin
start_date := to_number(to_char(to_date('2018-01-01', 'yyyy-MM-dd'), 'j'));
end_date := to_number(to_char(to_date('2018-01-31', 'yyyy-MM-dd'), 'j'));
for cur_r in start_date..end_date loop
work_date := to_char(to_date(cur_r, 'j'), 'yyyyMMdd');
dma.fill_account_turnover_f.fill(work_date);
end loop;
end;'
);
end;
Wouldn't it be simpler if you created a stored procedure and called it, instead of embedding that anonymous PL/SQL block into DBMS_SCHEDULER.CREATE_JOB call? Now you have to escape single quotes, i.e. use two consecutive ones every time. Something like this:
begin
DBMS_SCHEDULER.create_job (
job_name => 'J_ACCOUNT_TURNOVER_F',
job_type => 'PLSQL_BLOCK',
start_date => SYSTIMESTAMP, enabled => TRUE,
job_action =>
'declare
start_date number;
end_date number;
work_date date;
begin
start_date := to_number(to_char(to_date(''2018-01-01'', ''yyyy-MM-dd''), ''j''));
end_date := to_number(to_char(to_date(''2018-01-31'', ''yyyy-MM-dd''), ''j''));
for cur_r in start_date..end_date loop
work_date := to_char(to_date(cur_r, ''j''), ''yyyyMMdd'');
dma.fill_account_turnover_f.fill(work_date);
end loop;
end;'
);
end;
/
Maybe you're allergic to stored procedures :) Here is how you can do it without having to escape each individual quote. It is called the "Q Quote syntax".
DBMS_SCHEDULER.create_job (
job_name => 'J_ACCOUNT_TURNOVER_F',
job_type => 'PLSQL_BLOCK',
start_date => SYSTIMESTAMP, enabled => TRUE,
job_action =>
q'!declare
start_date number;
end_date number;
work_date date;
begin
start_date := to_number(to_char(to_date('2018-01-01', 'yyyy-MM-dd'), 'j'));
end_date := to_number(to_char(to_date('2018-01-31', 'yyyy-MM-dd'), 'j'));
for cur_r in start_date..end_date loop
work_date := to_char(to_date(cur_r, 'j'), 'yyyyMMdd');
dma.fill_account_turnover_f.fill(work_date);
end loop;
end;'
);
end;!'
More examples in this question

procedure scheduled job inside package

I have created a package purging inside that created procedure. How to schedule procedure around 2AM CST?
create or replace package body purging as
PROCEDURE del_exp IS
begin
FOR td IN (
SELECT
table_name
FROM
all_tables
where owner = 'ud_oi' and table_name not like 'lgh%'
)
LOOP
EXECUTE IMMEDIATE 'DELETE FROM ' || td.table_name || ' WHERE TRUNC(case_dt) < TRUNC(sysdate - 38)' ;
END LOOP;
end;
END del_exp;
A simple option is to use DBMS_JOB; if your database is recent, DBMS_SCHEDULER is preferred. You'd do it as follows:
DECLARE
X NUMBER;
BEGIN
SYS.DBMS_JOB.SUBMIT (
job => X,
what => 'begin purging.del_exp; end;',
next_date => TO_DATE ('16.06.2020 02:00:00', 'dd/mm/yyyy hh24:mi:ss'),
interval => 'TRUNC (SYSDATE+1) + 2 / 24',
no_parse => FALSE);
SYS.DBMS_OUTPUT.PUT_LINE ('Job Number is: ' || TO_CHAR (x));
COMMIT;
END;
/
A DBMS_SCHEDULER option (which also shows how to run it during working days (at least, working here where I live)):
BEGIN
DBMS_SCHEDULER.CREATE_JOB (
job_name => 'purging',
job_type => 'PLSQL_BLOCK',
job_action => 'begin purging.del_exp; end;',
start_date => TO_TIMESTAMP_TZ ('16.06.2020 02:00 Europe/Zagreb',
'dd.mm.yyyy hh24:mi TZR'),
repeat_interval => 'FREQ=DAILY; BYDAY=MON,TUE,WED,THU,FRI; BYHOUR=2; BYMINUTE=0',
enabled => TRUE,
comments => 'Purge tables');
END;
/
Just to mention: condition you wrote:
table_name not like 'lgh%'
looks suspicious. Table names are - by default - in UPPERCASE. Unless you create tables using mixed (or lower) case, you can do that by enclosing their names into double quotes. I hope you didn't/don't do that. Therefore, you'd rather use
table_name not like 'LGH%'

PLSQL block for run the job using dbms_scheduler for gather statistics of 30 schema

I want to create one PL/SQL block where try to run the job using dbms_scheduler package and I want to gather schema stats of all 30 schema. Eg:
begin
dbms_scheduler_create_job(
job_name => ....,
job_type = > 'PL/SQL BLOCK',
job_action => 'declare
sch_lst dbms_stats.objecttab := dbms_stats.objecttab()
begin
sch_lst.extend(10);
sch_lst(1).ownname := "ab"; --ab is the Schema name
sch_lst(2).ownname := "cd";
.........
sch_lst(30).ownname := "xy";
dbms_stats.gather_schema_stats( ......)
end;
/
',
start_date => sysdate,
..........);
end;
/
Before start_date => sysdate, remove / and also in the schema name instead of " (double quote) use '' (double single quote) because it is inside the declare statement which is already inside single quote.
begin
dbms_scheduler_create_job(
job_name => ....,
job_type = > 'PL/SQL BLOCK',
job_action => 'declare
sch_lst dbms_stats.objecttab := dbms_stats.objecttab()
begin
sch_lst.extend(10);
sch_lst(1).ownname := ''ab''; --ab is the Schema name
sch_lst(2).ownname := ''cd'';
.........
sch_lst(10).ownname := ''kl'';
dbms_stats.gather_schema_stats( ......)
end;
',
start_date => sysdate,
..........);
end;
/
Then after compile this one. you can check the job by using execute dbms_schedule.run_job('<job_name>');
Firstly, you may create such a procedure :
create or replace procedure pr_schema_stats is
sch_lst owa.vc_arr;
begin
sch_lst(1) := 'ab';
sch_lst(2) := 'cd';
sch_lst(3) := 'ef';
sch_lst(4) := 'gh';
sch_lst(5) := 'ij';
sch_lst(6) := 'kl';
sch_lst(7) := 'mn';
sch_lst(8) := 'op';
sch_lst(9) := 'rs';
sch_lst(10):= 'tu';
for i in 1..10
loop
dbms_stats.gather_schema_stats(upper(sch_lst(i)),degree => 4, cascade => true );
end loop;
end;
and then call from scheduler as :
declare
v_job_name varchar2(70) := 'jb_gather_stats';
begin
dbms_scheduler.create_job(
job_name => v_job_name,
job_type => 'STORED_PROCEDURE',
job_action => 'pr_schema_stats',
start_date => to_date('04-12-2018 19:00:00', 'dd-mm-yyyy hh24:mi:ss'),
repeat_interval => 'FREQ=MONTHLY;INTERVAL=1;',
auto_drop => false,
comments => 'Produces statistics for Cost based SQL statements');
dbms_scheduler.enable(v_job_name);
end;
EDIT : You can replace your procedure's code with :
create or replace procedure pr_schema_stats is
begin
for c in (
select u.username,
row_number() over (order by u.username) as rn
from dba_users u
where u.account_status = 'OPEN'
and u.username not like 'SYS%'
)
loop
begin
dbms_stats.gather_schema_stats(c.username,degree => 4, cascade => true );
exception when others then
dbms_output.put_line(sqlerrm);
end;
end loop;
end;
to include all of the ordinary schemas in the analyze task.

scheduled job is not launching

I would like to launch a scheduled job after every two hours starting from 04:15 tomorrow. The job should launch everyday and after every two hours. Something like at : 04:15, 06:15, 08:15....
The procedure is about creating file in a remote machine. When I test the procedure then it works just fine, and creates file in remote location. However, it fails as a job in dbms_jobs package. I am not sure what I am doing wrong. Here is the code of procedure:
CREATE OR REPLACE PROCEDURE ARC_HRVR.VR_AD_INTEGRATION_EXPORT AS
v_file UTL_FILE.file_type;
BEGIN
v_file := UTL_FILE.fopen('DIR_VR_AD_INTEGRATION', 'HRMtoAD1_'||to_char(sysdate,'YYYYMMDD')||'_'||to_char(sysdate,'HH24MISS'), 'w', 32767);
FOR x IN (
SELECT * FROM (SELECT
decode(pid, NULL, RPAD(' ',7,' '), RPAD(user_id, 7, ' '))|| '' ||
decode(o365, NULL, RPAD(' ',80,' '), RPAD(o365, 80, ' '))
str FROM table WHERE integrated = 'N') str WHERE rownum <= 1000 ORDER BY rownum)
´LOOP
BEGIN
UTL_FILE.put_line(v_file, x.str);
END;
END LOOP;
UTL_FILE.fflush(v_file);
UTL_FILE.fclose(v_file);
END VR_AD_INTEGRATION_EXPORT;
And here is the code for launching job:
DECLARE
l_id binary_integer;
begin
dbms_job.submit(job => l_id, what => 'ARC_HRVR.vr_ad_integration_export();', interval => 'TRUNC(SYSDATE)+1+4.25/24', );
dbms_output.put_line(l_id);
end;
A bit of guidance and tweaking will fix my code :-)
Thanks in advance
Are you putting in the job as the procedure owner (ARC_HRVR) or as a user that has access to execute the code?
Have you tried surrounding the 'what' in a execution block?
begin ARC_HRVR.vr_ad_integration_export(); end;
The job is launching, right? You see next_date getting updated in the view dba_jobs, etc?
You can refer this example
BEGIN
DBMS_SCHEDULER.create_job (
job_name => 'test_full_job_definition',
job_type => 'PLSQL_BLOCK',
job_action => 'BEGIN my_job_procedure; END;',
start_date => SYSTIMESTAMP,
repeat_interval => 'freq=hourly; byminute=0; bysecond=0;',
end_date => NULL,
enabled => TRUE,
comments => 'Job defined entirely by the CREATE JOB procedure.');
END;
/
and for more detail please go through this Scheduler

Resources