【问题标题】:Can we use a table type parameter as a default null parameter in PLSQL?我们可以使用表类型参数作为 PLSQL 中的默认空参数吗?
【发布时间】:2017-06-22 11:23:24
【问题描述】:

我有一个记录类型如下,

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); 

我已经使用这条记录创建了一个表类型:

TYPE x_rec_tab IS TABLE OF x_Rec INDEX BY PLS_INTEGER;

我想在过程中使用此表类型作为默认空参数。

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

它给出以下错误消息

PLS-00382:表达式类型错误

【问题讨论】:

  • 对我来说这种代码有效。你在哪一行得到错误,我认为它是在其他地方引发的。
  • 在过程的表类型参数中。我们也可以对表类型参数使用默认 null 吗?

标签: oracle plsql


【解决方案1】:

我通过在过程的签名中使用CAST(null as /*your_type*/) 解决了这个问题。

例如,在您的情况下,它将是这样的:

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

然后,在过程中,你只需要使用count方法检查x_rec_是否有元素。

这种方式适合我。

【讨论】:

  • 尽管接受的答案和回复的垃圾格式,这是最好的答案。接受的答案要求开发人员更改传入变量的数据类型,这并不总是容易做到(甚至可能?)
  • 有趣的是,如果您在函数内部检查 null (if x_rec_ is null),它可以区分 null 和 empty。但是,即使它 null,您仍然可以在没有 NPE 的情况下使用 for i in nvl(x_rec_.first, 0) .. nvl(x_rec_.last, -1) loop 等等。作为一个也用其他语言编程的人,这奇怪 - 但在这种情况下是受欢迎的,因为这意味着我可以调用其他函数而不必担心它们是否检查 null。
【解决方案2】:

an associative array 无法做到这一点,never be null 则可以。如果您尝试将 null 分配给 x_rec_tab 类型的变量,您将得到相同的错误。他们也don't have constructors,所以你不能使用空集合代替。

您可以使用varray 或更适合您的情况使用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.

您也可以默认为空集合:

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

如果您有其他依赖于类型的代码当然是关联数组,这对您并没有太大帮助。

【讨论】:

    【解决方案3】:

    老问题,但仍然可能会有所帮助。 你可以创建一个函数:

    function empty_tab
    return x_rec_tab
    as 
      l_tab x_rec_tab;
    begin
    
      return l_tab;
    
    end empty_tab;  
    

    这样你就可以(注意 empty_tab 被用作默认参数):

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

    【讨论】:

      【解决方案4】:

      这是对@ManuelPerez 答案的重复,但我只是觉得可以更好地解释。

      创建此过程,将您的可选变量转换为您的数据类型,如下所示:

      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;
      

      这优于公认答案的原因是它不需要您更改传入变量的数据类型。根据您的情况,您可能没有这样做的灵活性。

      如果你有一个变量来提供过程,现在像这样调用你的过程:

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

      如果你不这样做,也可以这样:

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

      您的输出将如下所示:

      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
      

      【讨论】:

        猜你喜欢
        • 2020-11-27
        • 2017-03-06
        • 1970-01-01
        • 2012-04-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-07-18
        • 2010-12-25
        相关资源
        最近更新 更多