首页 文章

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

提问于
浏览
13

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

举个例子,它是这样的(表名不同,但结构是一样的):

这是表的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 回答

  • 12

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

    在初始化之前,嵌套表或varray在原子上为null;集合本身是null,而不是它的元素 . 要初始化嵌套表或varray,请使用构造函数,这是一个与集合类型同名的系统定义函数 . 此函数根据传递给它的元素构造集合 . 您必须为每个varray和嵌套表变量显式调用构造函数 . 关联数组是第三种集合,不使用构造函数 . 只要允许函数调用,就允许构造函数调用 . 初始化和引用集合

    相比:

    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.
    

    EDIT 另请注意,关联数组可以是稀疏的 . 循环 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.
    
  • 5

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

    你're getting an exception raised on the loop is, as you'注意到,索引 emp.first 不存在的原因 .

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

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

相关问题