为什么PL / SQL中的空关联数组检查失败?

时间:2012-09-13 17:51:44

标签: oracle plsql oracle11g associative-array

我有一个由表列的行类型创建的关联数组。

举个例子,这是怎么回事(表名不同,但结构相同):

这是表格的DDL

CREATE TABLE employees
  (
     id     NUMBER,
     name   VARCHAR2(240),
     salary NUMBER
  ); 

以下是我的程序:

DECLARE
    TYPE table_of_emp
      IS TABLE OF employees%ROWTYPE INDEX BY BINARY_INTEGER;
    emp TABLE_OF_EMP;
BEGIN
    IF emp IS NULL THEN
      dbms_output.Put_line('Null associative array');
    ELSE
      dbms_output.Put_line('Not null');
    END IF;
END; 

我认为应该导致打印“Null associative array”。但是,if条件失败,执行跳转到else部分。

现在,如果我放入for循环来打印集合值

DECLARE
    TYPE table_of_emp
      IS TABLE OF employees%ROWTYPE INDEX BY BINARY_INTEGER;
    emp TABLE_OF_EMP;
BEGIN
    IF emp IS NULL THEN
      dbms_output.Put_line('Null associative array');
    ELSE
      dbms_output.Put_line('Not null');

      FOR i IN emp.first..emp.last LOOP
          dbms_output.Put_line('Emp name: '
                               || Emp(i).name);
      END LOOP;
    END IF;
END; 

然后程序单元引发异常,引用for循环线

  

ORA-06502:PL / SQL:数字或值错误

我认为是因为null关联数组。是否由于null关联数组而引发错误?

那么为什么第一次检查失败呢?我做错了什么?

数据库服务器是Oracle 11g EE(版本11.2.0.3.0 64位)

2 个答案:

答案 0 :(得分:13)

我认为这会导致打印“Null associative array”。这种假设对于关联数组是错误的。它们在声明时存在,但是是空的。对于其他类型的PL / SQL集合来说是正确的:

  

在初始化之前,嵌套表 varray 在原子上为空;   集合本身是null,而不是它的元素。初始化一个   嵌套表或varray,您使用构造函数,系统定义   与集合类型同名的函数。这个功能   从传递给它的元素构造集合。

     

您必须为每个varray和嵌套显式调用构造函数   表变量。 关联数组,第三种集合   不使用构造函数。无论函数在何处,都允许构造函数调用   电话是允许的。 Initializing and Referencing Collections

比较

SQL> declare
  2      type varchar2_100_aa is table of varchar2(100) index by binary_integer;
  3      test varchar2_100_aa;
  4  begin
  5      test(1) := 'Hello';
  6      dbms_output.put_line(test(1));
  7  end;
  8  /
Hello

PL/SQL procedure successfully completed.

SQL> declare
  2      type varchar2_100_va is varray(100) of varchar2(100);
  3      test varchar2_100_va;
  4  begin
  5      test(1) := 'Hello';
  6      dbms_output.put_line(test(1));
  7  end;
  8  /
declare
*
ERROR at line 1:
ORA-06531: Reference to uninitialized collection
ORA-06512: at line 5

正确完成变量数组:

SQL> declare
  2      type varchar2_100_va is varray(10) of varchar2(100);
  3      test varchar2_100_va;
  4  begin
  5      test := varchar2_100_va(); -- not needed on associative array
  6      test.extend; -- not needed on associative array
  7      test(1) := 'Hello';
  8      dbms_output.put_line(test(1));
  9  end;
 10  /
Hello

PL/SQL procedure successfully completed.

由于关联数组为空firstlast为空,这就是为什么第二个示例会导致ORA-06502: PL/SQL: Numeric or value error

SQL> declare
  2      type varchar2_100_aa is table of varchar2(100) index by binary_integer;
  3      test varchar2_100_aa;
  4  begin
  5      dbms_output.put_line(test.count);
  6      dbms_output.put_line(coalesce(to_char(test.first), 'NULL'));
  7      dbms_output.put_line(coalesce(to_char(test.last), 'NULL'));
  8      test(1) := 'Hello';
  9      dbms_output.new_line;
 10      dbms_output.put_line(test.count);
 11      dbms_output.put_line(coalesce(to_char(test.first), 'NULL'));
 12      dbms_output.put_line(coalesce(to_char(test.last), 'NULL'));
 13  end;
 14  /
0
NULL
NULL

1
1
1

PL/SQL procedure successfully completed.

编辑另请注意,关联数组可以是稀疏的。循环遍历firstlast之间的数字将引发任何稀疏集合的异常。而是使用firstnext,如下所示:( Lastprev来循环另一个方向。)

SQL> declare
  2      type varchar2_100_aa is table of varchar2(100) index by binary_integer;
  3      test varchar2_100_aa;
  4      i binary_integer;
  5  begin
  6      test(1) := 'Hello';
  7      test(100) := 'Good bye';
  8      dbms_output.put_line(test.count);
  9      dbms_output.put_line(coalesce(to_char(test.first), 'NULL'));
 10      dbms_output.put_line(coalesce(to_char(test.last), 'NULL'));
 11      dbms_output.new_line;
 12  --
 13      i := test.first;
 14      while (i is not null) loop
 15          dbms_output.put_line(to_char(i, '999')  || ' - ' || test(i));
 16          i := test.next(i);
 17      end loop;
 18  end;
 19  /
2
1
100

   1 - Hello
 100 - Good bye

PL/SQL procedure successfully completed.

答案 1 :(得分:5)

我不会回答为什么第一次检查失败。我从来没有想过会做那样的事情,我很惊讶它没有引起错误。

正如您所指出的那样,您在循环中获得异常的原因是索引emp.first不存在。

您应该检查是否存在此索引,而不是检查空值。你可以使用.exists(i)语法:

if not emp.exists(emp.first) then
   dbms_output.put_line('Nothing in here.');
end if;