简体   繁体   中英

Can we use a table type parameter as a default null parameter in PLSQL?

I have a record type as follows,

TYPE x_Rec IS RECORD(
   master_company          x_tab.master_company%TYPE,
   report_trans_type       x_tab.report_trans_type%TYPE,
   balance_version_id      x_tab.balance_version_id%TYPE,  
   reporting_entity        x_tab.reporting_entity%TYPE,
   year_period_from        x_tab.year_period%TYPE,
   year_period_to          x_tab.year_period%TYPE,
   journal_id              x_tab.journal_id%TYPE,
   row_id                  x_tab.row_id%TYPE); 

and I have created a table type using this record:

TYPE x_rec_tab IS TABLE OF x_Rec INDEX BY PLS_INTEGER;

I want to use this table type in a procedure as a default null parameter.

PROCEDURE x_Balance___(x_param IN NUMBER,
                       x_rec_  IN x_rec_tab default null)
IS
BEGIN
...My code
END;

It gives the following error message

PLS-00382: expression is of the wrong type

I resolved this by using CAST(null as /*your_type*/) in the Procedure's signature.

For instance, in your case, it will be something like this:

PROCEDURE x_Balance (x_param IN NUMBER,
                     x_rec_  IN x_rec_tab default cast(null as x_rec_tab))

Then, within the procedure, you just need to check if x_rec_ has elements by using the count method.

This way works for me.

You can't do that with an associative array , as that can never be null . You would get the same error if you tried to assign null to a variable of type x_rec_tab . They also don't have constructors , so you can't use an empty collection instead.

You can do this will a varray or more usefully for your situation a nested table :

create or replace package p42 as

TYPE x_Rec IS RECORD(
   master_company          x_tab.master_company%TYPE,
   report_trans_type       x_tab.report_trans_type%TYPE,
   balance_version_id      x_tab.balance_version_id%TYPE,  
   reporting_entity        x_tab.reporting_entity%TYPE,
   year_period_from        x_tab.year_period%TYPE,
   year_period_to          x_tab.year_period%TYPE,
   journal_id              x_tab.journal_id%TYPE,
   row_id                  x_tab.row_id%TYPE); 

 -- no index-by clause, so nested table not associative array
TYPE x_rec_tab IS TABLE OF x_Rec;

end p42;
/

Package P42 compiled

show errors

No errors.


create or replace package body p42 as

PROCEDURE x_Balance___(x_param IN NUMBER,
                       x_rec_  IN x_rec_tab default null)
IS
BEGIN
  --...My code
  null;
END;

PROCEDURE dummy IS
  l_rec_tab x_rec_tab;
BEGIN
  l_rec_tab := null;
END;

end p42;
/

Package Body P42 compiled

show errors;

No errors.

You could also default to an empty collection instead:

PROCEDURE x_Balance___(x_param IN NUMBER,
                       x_rec_  IN x_rec_tab default x_rec_tab())
IS
...

That doesn't really help you much if you have other code that relies on the type being an associative array of course.

Old question but still might be helpful. You can create a function:

function empty_tab
return x_rec_tab
as 
  l_tab x_rec_tab;
begin

  return l_tab;

end empty_tab;  

This way you can (notice that empty_tab is used as default parameter):

PROCEDURE x_Balance___(x_param IN NUMBER,
                       x_rec_  IN x_rec_tab default empty_tab)
IS
BEGIN
...My code
END;

This is a repeat of @ManuelPerez answer, but I just feel that it could have been explained better.

Create this procedure, casting your optional variable to your datatype like this:

CREATE OR REPLACE PROCEDURE Test_Procedure (
   txt_          IN  VARCHAR2,
   col_formats_  IN  dbms_sql.varchar2a DEFAULT cast(null as dbms_sql.varchar2a) )
IS BEGIN
   Dbms_Output.Put_Line (txt_);
   FOR i_ IN 1 .. 10 LOOP
      IF col_formats_.EXISTS(i_) THEN
         Dbms_Output.Put_Line (i_ || ' Exists');
      ELSE
         Dbms_Output.Put_Line (i_ || ' DOES NOT Exist');
      END IF;
   END LOOP;
END Test_Procedure;

The reason this beats the accepted answer is that it doesn't require you to change the datatype of the incoming variable. Depending on your circumstance, you may not have the flexibility to do that.

Now call your procedure like this if you have a variable to feed the procedure:

DECLARE
   txt_   VARCHAR2(100) := 'dummy';
   arr_   dbms_sql.varchar2a;
BEGIN
   arr_(4) := 'another dummy';
   Test_Procedure (txt_, arr_);
END;

Or like this if you don't:

DECLARE
   txt_   VARCHAR2(100) := 'dummy';
BEGIN
   Test_Procedure (txt_);
END;

Your output will look something like this:

dummy
1 DOES NOT Exist
2 DOES NOT Exist
3 DOES NOT Exist
4 Exists
5 DOES NOT Exist
6 DOES NOT Exist
7 DOES NOT Exist
8 DOES NOT Exist
9 DOES NOT Exist
10 DOES NOT Exist

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM