我们可以使用表类型参数作为 PLSQL 中的默认空参数吗?

Posted

技术标签:

【中文标题】我们可以使用表类型参数作为 PLSQL 中的默认空参数吗?【英文标题】:Can we use a table type parameter as a default null parameter in 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 吗? 【参考方案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

【讨论】:

以上是关于我们可以使用表类型参数作为 PLSQL 中的默认空参数吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何将表作为参数传递并使用 plsql 过程填充该表

PLSQL中的内存表--Index By Table

如何在 Oracle SQL Developer 的存储过程中将表名列表作为参数传递?如何使用 PLSQL VARRAY 或嵌套表?

c# 中的可空类型是啥?

PLSQL 中的查询参数定义

plsql解析文本文件的输出并插入表