我们可以使用表类型参数作为 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 中的默认空参数吗?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Oracle SQL Developer 的存储过程中将表名列表作为参数传递?如何使用 PLSQL VARRAY 或嵌套表?