PLS-00306错误:Oracle PL/SQL数组DELETE方法参数异常求助
解决PLS-00306错误:调用DELETE时参数数量或类型错误
嘿,这个错误我太熟悉了!问题的核心在于你定义的DateArray大概率是VARRAY(可变数组)类型,而Oracle里VARRAY的DELETE方法根本不支持传入索引参数——它要么不带参数清空整个集合,要么就没有按索引删除的重载。只有**嵌套表(Nested Table)**类型的集合才允许用DELETE(index)来删除指定位置的元素。
下面给你两种可行的解决方案,按需选择:
方案1:把集合类型改成嵌套表(最直接)
如果你的业务场景允许修改DateArray的类型定义,这是最快解决问题的办法:
- 先删掉原来的VARRAY类型(如果已经创建):
DROP TYPE DateArray;
- 重新创建成嵌套表类型:
CREATE TYPE DateArray AS TABLE OF DATE;
改完类型后,你原来代码里的o_dates.delete(i);就能正常跑了。不过要提醒你:嵌套表删除元素后会留下索引"空隙",后续遍历的时候最好用FIRST+NEXT的方式,避免遇到空元素报错:
i := o_dates.FIRST; WHILE i IS NOT NULL LOOP -- 你的处理逻辑 i := o_dates.NEXT(i); END LOOP;
方案2:不修改集合类型,用临时集合过滤元素
要是不能改DateArray的类型(比如其他业务模块依赖这个VARRAY),那就换个思路:创建一个临时集合,把非节假日的日期筛选进去,最后赋值给输出参数。
修改后的LeaveDates4存储过程代码如下:
create or replace PACKAGE BODY MYPACKAGE AS PROCEDURE LeaveDates4 ( I_STDATE IN DATE, I_ENDDATE IN DATE, O_DATES OUT DateArray ) AS n INTEGER := LEAST( I_ENDDATE - I_STDATE, 29 ); H_dates DateArray; x number; is_holiday BOOLEAN; -- 临时集合存过滤后的非节假日日期 temp_dates DateArray := DateArray(); BEGIN select count(*) into x from TSL_HOLIDAYLIST; O_DATES := DateArray(); H_dates := DateArray(); O_DATES.EXTEND( n + 1 ); dbms_output.put_line(n); dbms_output.put_line(x); -- 初始化原始日期数组 FOR i IN 0 .. n LOOP O_DATES(i+1) := I_STDATE + i; dbms_output.put_line(I_STDATE + i); END LOOP; -- 加载所有节假日日期到集合 for cur in (select HOLIDAY_DATE from TSL_HOLIDAYLIST) loop h_dates.extend; h_dates(h_dates.last):= cur.HOLIDAY_DATE; end loop; -- 过滤非节假日日期到临时集合 FOR i IN O_DATES.first..O_DATES.last LOOP is_holiday := FALSE; -- 检查当前日期是否是节假日 FOR j IN h_DATES.first..h_DATES.last LOOP if o_dates(i) = h_dates(j) then is_holiday := TRUE; EXIT; -- 找到匹配就跳出,不用继续查 end if; end loop; -- 不是节假日就加入临时集合 IF NOT is_holiday THEN temp_dates.EXTEND; temp_dates(temp_dates.LAST) := o_dates(i); END IF; end loop; -- 把过滤后的结果赋值给输出参数 O_DATES := temp_dates; END LeaveDates4; END MYPACKAGE;
额外优化小技巧
- 内层循环找到匹配后用
EXIT跳出,能减少不必要的遍历,提升性能。 - 可以用Oracle集合的
MEMBER OF操作符替代内层循环,代码更简洁:
-- 替换原来的内层循环判断 IF o_dates(i) NOT MEMBER OF h_dates THEN temp_dates.EXTEND; temp_dates(temp_dates.LAST) := o_dates(i); END IF;
这样一行代码就能完成是否是节假日的判断,省去了内层循环的代码。
内容的提问来源于stack exchange,提问作者Shilpa M B
相关产品推荐
相关产品推荐

