Skip to Main Content
  • Questions
  • DBMS_JOB -- how to pass parameters to the job

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question, Subhash.

Asked: March 11, 2001 - 11:13 pm UTC

Last updated: January 11, 2022 - 2:43 am UTC

Version: 8.0.5

Viewed 10K+ times! This question is

You Asked

Hi Tom

I have one procedure execute_job with two in parameters
(batchnumber and loaddate). Procedure as follows :-


create or replace procedure execute_job(batchnumber in number, Loaddate in varchar2)
is
l_theCursor integer default dbms_sql.open_cursor;
l_status integer;
p_sql varchar2(200);
v_job number;
BEGIN
p_sql :='alter session set nls_date_format= ''dd-mon-yyyy
hh24:mi:ss'' ';
dbms_sql.parse(l_theCursor,p_sql,dbms_sql.native);
l_status := dbms_sql.execute(l_theCursor);
dbms_sql.close_cursor(l_theCursor);
dbms_job.submit(v_job , 'fileimportedi.LoadFileLater
(batchnumber);', Loaddate, null);
commit;
END;


My problem is :-

when i execute my procedure with following parameters :-

Execute execute_job(347,'07-mar-2001 19:10:10');

Error comes :-

ERROR at line 1:
ORA-06550: line 1, column 117:
PLS-00201: identifier 'BATCHNUMBER' must be declared
ORA-06550: line 1, column 93:
PL/SQL: Statement ignored
ORA-06512: at "SYS.DBMS_JOB", line 72
ORA-06512: at "SYS.DBMS_JOB", line 140
ORA-06512: at "WMS.EXECUTE_JOB2", line 13
ORA-06512: at line 1

If i changed my dbms_job.submit as follows :-
dbms_job.submit(v_job , 'fileimportedi.LoadFileLater(347);',
Loaddate, null);

then it's run successfully(no error comes) and job successfully submitted in user_jobs table.

+++

Can we pass batchnumber as parameter for another packaged procedure or not ? if yes then how?



Thanks

Subhash



and Connor said...

What you should do is to create a parameter table:

create table parameters
( jobid number PRIMARY KEY,
batch number,
<any other inputs here>
);

and you would then:

....
dbms_job.submit(v_job , 'fileimportedi.LoadFileLater(JOB);',loadDate );
insert into parameters(v_job,batchnumber);
......

Every job can have access to its job number as a parameter like that. That would be used to look up the relevant data. The reason for doing this is so you are submitting the SAME sql string over and over again to the job queue --

fileimportedi.LoadFileLater(JOB);

and not:

fileimportedi.LoadFileLater(1);
fileimportedi.LoadFileLater(2);
fileimportedi.LoadFileLater(3);

which would tend to trash your shared pool with lots of UNIQUE sql.

Your loadFileLater routine should delete from the parameter upon successful completion or you could submit:

'fileimportedi.LoadFileLater(job);
declare
l_job number default job;
begin
delete from parameter where jobid = l_job;
end;'

which would do it automatically for you if loadfilelater succeeded (the delete would be skipped if the job failed)


short of that, you would have to code:


dbms_job.submit(v_job ,
'fileimportedi.LoadFileLater(' || batchNumber || ');',
Loaddate, null);

but that, as i said, would generate UNIQUE sql for each job which is BAD.

Note: There are some anomalies with this approach depending the version of 19c you are using. See this post

https://connor-mcdonald.com/2020/09/03/dbms_job-and-19c-code-changes-needed/



Rating

  (20 ratings)

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

Comments

DBMS_JOB

Ruben, May 21, 2002 - 4:17 pm UTC

Hi,

I am trying to call a pl/sql procedure from a form, i want the form to unbind after it makes the call to the pl/sql procedure as the procedure is huge and takes a lot of time to execute, for this i want to call the procedure in a DBMS_JOB.Please can you illustrate how to go about doing the same.(lets assume that the procedure needed to be invoked is temp(a,b)).

Tom Kyte
May 21, 2002 - 6:00 pm UTC

declare
l_job number;
begin
dbms_job.submit( l_job, 'temp( ' || a || ',' || b || ');' );
commit;
end;

is one way to do it.

If you plan on running temp lots with different inputs do this instead:

create table temp_parms( job_id number primary key, a number, b date );

declare
l_job number;
begin
dbms_job.submit( l_job, 'temp( JOB );' );
insert into temp_parms( l_job, a, b );
commit;
end;


and have TEMP query temp_parms by job_id -- which we passed in -- to get its parameters (makes better use of binding and that is important)





Conditions for substitution of JOB

Dany, June 27, 2003 - 3:15 am UTC

Hi Tom,

under what conditions is the JOB keyword replaced by the actual job id? I have not been able to find documentation to cover this.

The test below seems to indicate that it's multiple times, selective, and there's some magic in there!

Note that in the dbms_job the INSERT SELECT statement refers to column JOB in the WHERE clause but that does not get replaced otherwise we would have more than two rows in test1; the last statement shows that there are 12 other jobs for this user.

NPIVS@MDMD.WORLD> create table test1 (job_id number, text varchar2(4000));

Table created.

NPIVS@MDMD.WORLD> get afiedt.sql
1 declare l_job_id number := NULL;
2 begin
3 dbms_job.submit (l_job_id,
4 'DECLARE l_job NUMBER := JOB;' ||
5 'BEGIN ' ||
6 'INSERT INTO TEST1 (job_id, text) SELECT JOB, SUBSTR(WHAT, 1, 4000 - 39) || '' '' || JOB FROM USER_JOBS WHERE JOB = l_jo
b;' ||
7 'INSERT INTO TEST1 (job_id, text) values (JOB, ''The job id is '' || JOB);' ||
8 'COMMIT;' ||
9 'END;');
10* end;
NPIVS@MDMD.WORLD> /

PL/SQL procedure successfully completed.

NPIVS@MDMD.WORLD> commit;

Commit complete.

NPIVS@MDMD.WORLD> -- Some time passes
NPIVS@MDMD.WORLD> -- Check job is complete
NPIVS@MDMD.WORLD> select job, what, this_date, next_date, failures from user_jobs where what like 'DECLARE l_job %';

no rows selected

NPIVS@MDMD.WORLD> -- Job has completed so it had no failures
NPIVS@MDMD.WORLD> select * from test1;

JOB_ID
----------
TEXT
------------------------------------------------------------
1585450
DECLARE l_job NUMBER := JOB;BEGIN INSERT INTO TEST1 (job_id,
text) SELECT JOB, SUBSTR(WHAT, 1, 4000 - 39) || ' ' || JOB
FROM USER_JOBS WHERE JOB = l_job;INSERT INTO TEST1 (job_id,
text) values (JOB, 'The job id is ' || JOB);COMMIT;END; 1585
450

1585450
The job id is 1585450


NPIVS@MDMD.WORLD> select count(*) from user_jobs where 45 = 45;

COUNT(*)
----------
12

NPIVS@MDMD.WORLD>

Tom Kyte
June 27, 2003 - 8:55 am UTC

see
</code> http://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:9088073430469#9099572884547 <code>

it is very consistent actually.


I don't see what in your test leads you to believe in magic? You submit a job that inserts 2 rows -- and it did. It ran a query:

insert into ...
select ... from user_jobs where JOB = :x

(job being a COLUMN in a database table in that context, not a PLSQL variable)

Your standalong query with 45=45 is the same as where 1=1 or simply:

select count(*) from user_jobs;




Re: Conditions for substitution of JOB

Dany, June 28, 2003 - 6:28 am UTC

Okay thanks for that.

I had incorrectly thought that it was some sort of string substitution but your reference indicates it is the standard PL/SQL re-writing of SQL statements to use bind variables.

Cheers
Dany

question on dbms_job

A reader, October 17, 2003 - 11:24 am UTC

I understand that dbms_jobs are executed as anonymous pl/sql blocks. There is a claim being made in our team
that these anonymous pl/sql blocks are being parsed
again and again. Following is an example

DECLARE job BINARY_INTEGER := :job; next_date DATE := :mydate;
broken BOOLEAN := FALSE; BEGIN pkg1.procedure1();
:mydate := next_date; IF broken THEN :b := 1; ELSE :b := 0;
END IF; END;

Is there anything wrong with the way we are using
dbms_job? Any other comments?

Thanx!

Tom Kyte
October 17, 2003 - 12:42 pm UTC

sure, they are getting soft parsed each time they are executed. the job queue process

a) queries to find jobs
b) finds the jobs
c) builds the above block
d) parse/executes it


but it is a soft parse the 2cnd, 3rd, 4th, nth time. Should be just fine. Is there a percieved issue here? I mean the jobs are not running 50 times a second -- more like 50 seconds between runs at best (more likely much longer)

I agree!

A reader, October 17, 2003 - 5:23 pm UTC

Yeah, in my experiments, I have already noticed that
the subsequent parses are soft...I think it is just what
is happenning in the job that is taking time. Then
someone sees in top sql an anonymous block - euqtes it
to multiple parsing and files a bug. But I just wanted
to make sure with you that we are not doing anything
wrong here..

Thanx!

JOBS$ and ORA-00932

Naveen, July 29, 2004 - 5:39 am UTC

When executed select * from jobs$
after migration of the 8.1.7.4 - 64bits database to 9.2.0.5.0 - 64bit
it throws me an error 'ORA-00932' What can i do to sovle this..?

Tom Kyte
July 29, 2004 - 11:48 am UTC

don't query job$?

use dba_jobs to query the job queues, would you query obj$ to find out what tables you have (no)... You would query dba_objects.




Very useful

Prasad Gunaratne, January 23, 2005 - 11:57 pm UTC

Yet another example of Oracle docs were insufficient

Passing parameter to Job

Laxman S Kondal, April 11, 2005 - 1:08 pm UTC

Hi Tom

Is there any way to pass parameter in dbms_job.submit without having parameter table? I am getting this error and I did find some where you showed an example but cant find it now.

lkondal@ORA9i> DECLARE
2 n NUMBER;
3 p_userlogin varchar2(15) := 'lk';
4 BEGIN
5 dbms_job.submit(n,
6 'P_Exp_Imp2.call_Exp( '|| p_userlogin||');' ,
7 SYSDATE);
8 COMMIT;
9 END;
10 /
DECLARE
*
ERROR at line 1:
ORA-06550: line 1, column 114:
PLS-00201: identifier 'LK' must be declared
ORA-06550: line 1, column 93:
PL/SQL: Statement ignored
ORA-06512: at "SYS.DBMS_JOB", line 79
ORA-06512: at "SYS.DBMS_JOB", line 136
ORA-06512: at line 5


lkondal@ORA9i>

I tried with various combination of quotes and || but all resulted in error or insteat of passing value of p_userlogin it goes as p_userlogin.

Whats the concept/rule/way to pass string in parameter?
Thanks.

Regards.

Tom Kyte
April 11, 2005 - 1:18 pm UTC

lk is a string, the block of code you want to submit to the job queue would have to look like:

p_exp_imp2.call_exp( 'lk' );

so you need to submit

....
'p_exp_imp2.call_exp( ''' || p_userlogin || ''');',
...

the '' is how to get a single ' into a character string literal.

Passing parameter to Job

Laxman S Kondal, April 11, 2005 - 1:41 pm UTC

Hi Tom

Thanks a lot and it works and I now know what is it.

Thanks and Regards.

large parameters

Gabriel, August 29, 2006 - 2:04 pm UTC

Hello Tom,

The technique of submitting a job together with inserting values into a parameter table seems very efficient for small paramters.
How would you pass an array of lets say 1.000.000 primary keys to a process submitted by a job. We have a "manager" procedure that runs a query that returns 5.000.000 primary keys to delete. We would like to do this in parallel with 5 processes submitted with jobs. The same technique can be applied if we want to delete from several tables at the same time, pass a list of 1.000.000 rows and a table name to a job and let it run on its own. If the procedures was called in the same session we would pass the list as an array with nocopy, but given that the what of the job is a string that doesn't quite work.
How would you accomplish something like that(besides using pipes)?

Thank you very much,

Tom Kyte
August 29, 2006 - 4:39 pm UTC

and how would you do it without using a TABLE???


pipes would not be anything I would even begin to consider, a table seems most appropriate here.

yes but...

Gabriel, August 29, 2006 - 8:16 pm UTC

Hello Tom,

Using a table would mean writting everything back to disk. I was hoping we can avoid that somehow. Is that possible?

Tom Kyte
August 30, 2006 - 8:04 am UTC

it is a job, it is GOING TO RUN IN THE BACKGROUND LATER. If you do not persist the data to disk???!?! How will the job get it?

putting 5,000,000 things into pipes (in the SGA) - not a good idea.

putting 5,000,000 things into a table (which is buffered in a reasonable fashion in the SGA) - good idea.

Unless you can simply send "ranges" or let the JOBS themselves figure out what records to delete (eg: instead of a master process looking at all records to find the 5million, tell job one "hey, you look at 1 through 2,000,000 and find the ones to delete", tell job two "hey, you look at 2,000,001 through 4,000,000 ok", job three....)

Inserting into parameter table after submitting the job?

Prashant Tambe, October 08, 2007 - 8:59 pm UTC

Tom,
I read your first reply and you say:

....
dbms_job.submit(v_job , 'fileimportedi.LoadFileLater(JOB);',loadDate );
insert into parameters(v_job,batchnumber);
......

My question is why would you INSERT into the parameter table AFTER submitting the job? Shouldn't you be doing that BEFORE submitting the job? I understand that you still need to COMMIT before the job runs. But any logical reason why the INSERT should be done afterwards?

Thank you.

Understood

Prashant Tambe, October 10, 2007 - 12:48 pm UTC

I understand why you are doing it that way. You need the JOB value to pass to the INSERT statement.

Passing parameters through DBMS_JOB.SUBMIT.

Igor, April 30, 2009 - 3:11 pm UTC

Tom,

I use DBMS_JOB.SUBMIT from a database trigger to call a package and to pass a barcode_no value as a VARCHAR2 parameter to that package. The parameter has values like `00000026¿, or `00057¿.
However, the package always receives value like `26¿ or `57¿ which is not what I need. I need the same value I passed in.
Everything in the trigger and the package declared as VARCHAR2.
Is is Oracle bug?

Tom Kyte
April 30, 2009 - 6:24 pm UTC

no, it is your bug.

you are using a number someplace, to a number 00001, 01 01.0, +1 are all the same thing - 1

you would really need to "give us an example", then we can

a) point out where you went wrong.
b) tell you how to do it properly.


(actually, (b) is done above, use the table to pass parameters)

Could I rely that the value of JOB returned by DBMS_JOB.SUBMIT is always unique

Vladimir Popov, February 13, 2011 - 10:23 am UTC

Hi Tom,

In your first answer to the question you use an example with parameter table. Since I want to keep the record inserted there for history purposes along with some more useful information gathered during the execution, could I rely that DBMS_JOB.SUBMIT will always return unique values of the JOB parameter that is passed. By always I mean really always - the same job will be started multiple times maybe for years, until dismissed :-).
Tom Kyte
February 14, 2011 - 7:49 am UTC

it is not documented, however, dbms_job.submit issues:

SELECT JOBSEQ.NEXTVAL 
FROM
 DUAL


so it should be unique unless they change the implementation sometime in the future.

If you wanted to truly 'bullet proof this', you could place your unique constraint on "job_number, date_completed" - and have your job update the date_completed record as its last line of code.

Or move your completed jobs into another table with your own key - so you have pending jobs in table 1 and completed jobs in table 2.


But - it should be OK as is unless they radically change the implementation.

passing Varchar2 table as job parameters

Dapio, March 29, 2012 - 9:07 am UTC

Hi there!
I have a similar problem:
I have a procedure with a VARCHAR2 table as parameter. I send VARCHAR2 table from java to this procedure and it works fine, but i need create a job, which run the same procedure with the same VARCHAR2 parameter. How to do this.

I have:

CREATE OR REPLACE TYPE "VARCHAR2_TABLE" IS TABLE OF VARCHAR2(300)

PROCEDURE PPP1(param1 IN VARCHAR2_TABLE) IS
BEGIN
...
END;

and i need to create procedure, creating the job from the interface like that:

PROCEDURE JOB_PPP1(param1 IN VARCHAR2_TABLE) IS
BEGIN
SYS.dbms_scheduler.create_job(
job_name => 'JOB_NAMED_PPP'
,job_type => 'PLSQL_BLOCK'
,program_name => 'PPP1'
,number_of_arguments => 1
,start_date => SYSTIMESTAMP
,repeat_interval => NULL
,enabled => TRUE
,comments => 'JOB Procedure PPP1'
);

SYS.dbms_scheduler.SET_JOB_ARGUMENT_VALUE ('JOB_NAMED_PPP', 1, param1 );
COMMIT;
END;


Thanks for helping

Tom Kyte
March 29, 2012 - 10:16 am UTC

you can use set_job_anydata_value

Here is a working example:

https://forums.oracle.com/forums/thread.jspa?threadID=480151#1720826

Retrieving JOB LOG_ID in a scheduled stored procedure

BC, August 14, 2012 - 10:20 pm UTC

Tom,

Is there a way to retrieve the JOB's LOG_ID in a procedure scheduled using dbms_scheduler ?

Thanks

BC

Passing procedure name having multiple parameters

shailesh, August 28, 2015 - 1:01 pm UTC

I have to do multi threading inside a package for which i am using DBMS_SCHEDULER.RUN_JOB. can any one help me with how to call the same.

JOB variable behaviour changed!

Nandhakumar Ramalingam, December 20, 2021 - 5:39 am UTC

I know we are not supposed to be using DBMS_JOB in 19c, but we support a legacy application where nothing much is allowed to be changed.

Interestingly, we are getting "wrong number of arguments in call to JOB" when we try this.

l_job number default job;


Any thoughts, Tom?

Adding to that...

Nandhakumar Ramalingam, December 20, 2021 - 5:50 am UTC

This doesn't work either...

dbms_job.submit( l_job, 'temp( JOB );' );


l_job and JOB do not have the same value in 19c!

More to Explore

Scheduler

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