ORA-06530: Ссылка на неинициализированный композит, даже если он инициализирован

Я прочитал решения для устранения ошибки, но я не знаю, почему я все еще получаю сообщение об ошибке,

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:

Сообщение об ошибке -

ORA-06530: Ссылка на неинициализированный композит

ORA-06512: в строке 14

  1. 00000 - "Ссылка на неинициализированный композит"

*Причина: Объект, большой объект или другой составной объект упоминался как левая сторона без инициализации.

*Действие: Инициализируйте композит с помощью соответствующего конструктора или присваивания всего объекта.


person SajjaD    schedule 07.01.2016    source источник
comment
у вас нет ПОСЛЕДНЕГО тега данных в это время, поэтому он неинициализируется   -  person Thomas    schedule 07.01.2016


Ответы (1)


Синтаксис, который вы используете, работает для 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, вы должны использовать конструктор объектов для вставки в таблицу этого объекта.

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

ОБНОВЛЕНИЕ: чтобы открыть курсор в коллекции

Вы должны использовать курсор ссылки, чтобы получить значение из коллекции, используя функцию TABLE и функцию CAST, чтобы помочь оракулу определить тип данных коллекции.

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
person San    schedule 07.01.2016
comment
теперь, если я хочу выбрать из таблицы tmp_tbl, как я могу это сделать? (вытащите его к курсору) - person SajjaD; 07.01.2016
comment
как я могу выполнять операции DML с этими таблицами типов коллекций? - person SajjaD; 13.01.2016
comment
Вы не можете запускать DML непосредственно для типов коллекций. Вам нужно найти индекс записи, которую вы хотите обновить, а затем обновить ее, используя тот же индекс. например - tmp_tbl(i).code := 99;, где i — индекс записи, которую необходимо обновить. - person San; 13.01.2016
comment
делает ли эта ссылка своего рода DML для таблиц типа коллекции? или это что-то другое? - person SajjaD; 13.01.2016
comment
чтобы вернуться к вашему последнему комментарию, могу ли я обновить индекс таким образом: tmp_tbl(i).code := tmp_tbl(i).code + 18; , или мне нужно сделать как ссылку oracle-base, о которой я упоминал? - person SajjaD; 13.01.2016
comment
Ссылка не делает ничего лишнего по сравнению с тем, что вы делаете, я не вижу, чтобы в приведенном там примере происходило какое-либо ОБНОВЛЕНИЕ. А для tmp_tbl(i).code := tmp_tbl(i).code + 18; я бы сказал ДА. - person San; 13.01.2016
comment
Какова наилучшая практика использования Oracle OBJECTs & RECORDs, я имею в виду, какой из них лучше для производительности или чего-то еще, чего я не знаю ...? - person SajjaD; 14.01.2016
comment
ОБЪЕКТЫ и ЗАПИСИ имеют более или менее одну и ту же цель, но ОБЪЕКТЫ находятся на уровне базы данных, который после создания может использоваться во многих процедурах, где, поскольку ЗАПИСИ имеют область действия в рамках процедуры, в которой они созданы. Вы можете открыть курсор на ОБЪЕКТАХ, но не на ЗАПИСЯХ. Вы также можете проверить глобальные временные таблицы, которые работают так же, как и обычные таблицы, но DML операции выполняются быстрее, чем обычные таблицы, и их объем ограничен текущим сеансом. - person San; 14.01.2016