ORA-06530: "Reference to uninitialized composite" 即使已初始化

ORA-06530: "Reference to uninitialized composite" even if initialized

我已经阅读了解决错误的解决方案,但我不知道为什么我仍然会出错,

CREATE OR REPLACE TYPE tmp_object IS OBJECT (
            id      NUMBER,
            code    NUMBER
            );
CREATE OR REPLACE TYPE tmp_table IS TABLE OF tmp_object;

以及使用它们的匿名块:

DECLARE
    cnt         PLS_INTEGER;
    tmp_tbl     tmp_table := tmp_table();
BEGIN
    SELECT regexp_count('34, 87, 908, 123, 645', '[^,]+', 1) str
    INTO cnt
    FROM dual;

    DBMS_OUTPUT.PUT_LINE('Counter is: ' || cnt);

    FOR i IN 1..cnt
    LOOP
        tmp_tbl.EXTEND;
        SELECT TRIM(REGEXP_SUBSTR('34, 87, 908, 123, 645', '[^,]+', 1,i)) str
        INTO tmp_tbl(tmp_tbl.LAST).code
        FROM dual;
        DBMS_OUTPUT.PUT_LINE(tmp_tbl(i).code);
    END LOOP;
END;

我使用 Oracle Database 12c,下面是 SQL Developer 4.2 中的错误:

Error report -

ORA-06530: Reference to uninitialized composite

ORA-06512: at line 14

  1. 00000 - "Reference to uninitialized composite"

*Cause: An object, LOB, or other composite was referenced as a left hand side without having been initialized.

*Action: Initialize the composite with an appropriate constructor or whole-object assignment.

您使用的语法适用于 RECORD

SQL> set serverout on;
SQL> 
SQL> DECLARE
  2      cnt         PLS_INTEGER;
  3      l_code      NUMBER;
  4      TYPE tmp_object IS RECORD (
  5              id      NUMBER,
  6              code    NUMBER
  7              );
  8      TYPE tmp_table IS TABLE OF tmp_object;
  9      tmp_tbl     tmp_table := tmp_table();
 10  BEGIN
 11      SELECT regexp_count('34, 87, 908, 123, 645', '[^,]+', 1) str
 12      INTO cnt
 13      FROM dual;
 14  
 15      DBMS_OUTPUT.PUT_LINE('Counter is: ' || cnt);
 16  
 17      FOR i IN 1..cnt
 18      LOOP
 19          tmp_tbl.EXTEND;
 20  
 21          SELECT TRIM(REGEXP_SUBSTR('34, 87, 908, 123, 645', '[^,]+', 1,i)) str
 22          INTO tmp_tbl(tmp_tbl.LAST).code
 23          FROM dual;
 24          DBMS_OUTPUT.PUT_LINE(tmp_tbl(i).code);
 25  
 26      END LOOP;
 27  END;
 28  /

Counter is: 5
34
87
908
123
645

PL/SQL procedure successfully completed

要使用 OBJECT,您必须使用对象构造函数插入到该对象的 table

SQL> 
SQL> CREATE OR REPLACE TYPE tmp_object IS OBJECT (
  2              id      NUMBER,
  3              code    NUMBER
  4              );
  5  
  6  /

Type created

SQL> CREATE OR REPLACE TYPE tmp_table IS TABLE OF tmp_object;
  2  /

Type created

SQL> 
SQL> DECLARE
  2      cnt         PLS_INTEGER;
  3      tmp_tbl     tmp_table := tmp_table();
  4  BEGIN
  5      SELECT regexp_count('34, 87, 908, 123, 645', '[^,]+', 1) str
  6      INTO cnt
  7      FROM dual;
  8  
  9      DBMS_OUTPUT.PUT_LINE('Counter is: ' || cnt);
 10  
 11      FOR i IN 1..cnt
 12      LOOP
 13          tmp_tbl.EXTEND;
 14  
 15          SELECT tmp_object(i, TRIM(REGEXP_SUBSTR('34, 87, 908, 123, 645', '[^,]+', 1,i)))
 16          INTO tmp_tbl(tmp_tbl.last)
 17          FROM dual;
 18  
 19          DBMS_OUTPUT.PUT_LINE(tmp_tbl(i).code);
 20      END LOOP;
 21  END;
 22  /

Counter is: 5
34
87
908
123
645

PL/SQL procedure successfully completed

更新:打开集合上的游标

You have to use a ref cursor to collect the value from the collection using TABLE function and CAST function to help oracle identify the datatype of the collection.

SQL> DECLARE
  2      cnt      PLS_INTEGER;
  3      tmp_tbl  tmp_table := tmp_table();
  4      c_cursor SYS_REFCURSOR;
  5      l_id     NUMBER;
  6      l_code   NUMBER;
  7  BEGIN
  8      SELECT regexp_count('34, 87, 908, 123, 645', '[^,]+', 1) str INTO cnt FROM dual;
  9  
 10      dbms_output.put_line('Counter is: ' || cnt);
 11  
 12      FOR i IN 1 .. cnt LOOP
 13          tmp_tbl.extend;
 14  
 15          SELECT tmp_object(i, TRIM(regexp_substr('34, 87, 908, 123, 645', '[^,]+', 1, i)))
 16            INTO tmp_tbl(tmp_tbl.last)
 17            FROM dual;
 18  
 19      END LOOP;
 20  
 21      OPEN c_cursor FOR
 22          SELECT * FROM TABLE(CAST(tmp_tbl AS tmp_table));
 23      LOOP
 24          FETCH c_cursor
 25              INTO l_id,
 26                   l_code;
 27          EXIT WHEN c_cursor%NOTFOUND;
 28          dbms_output.put_line(l_id || ',' || l_code);
 29      END LOOP;
 30      CLOSE c_cursor;
 31  
 32  END;
 33  /

Counter is: 5
1,34
2,87
3,908
4,123
5,645

PL/SQL procedure successfully completed