ORA-22905 - при запросе типа таблицы с помощью инструкции select

 DECLARE
 TYPE record_AB IS RECORD
   (
      AA              VARCHAR2 (16 BYTE),
      BB    VARCHAR2 (16 BYTE)
   );

  TYPE type_tab_AB IS TABLE OF record_AB
                        INDEX BY BINARY_INTEGER;

  tab_AB   type_tab_AB;

  BEGIN
   SELECT *
    BULK COLLECT INTO tab_AB FROM...
    ..
    SELECT * FROM TABLE (tab_AB) ;

Я получаю" ORA-22905: не удается получить доступ к строкам из не вложенного элемента таблицы", когда он попадает в инструкцию SELECT from TABLE.

возможно ли вообще запросить тип таблицы в PLSQL?

2 ответов


можно запрашивать типы таблиц в PL/SQL, но только вложенные таблицы и varrays, типы которых объявлены на уровне схемы, т. е. вне PL / SQL.

ошибка

ORA-22905: не удается получить доступ к строкам из не вложенного элемента таблицы

означает, что вы пытаетесь выполнить запрос из неподдерживаемого типа. Твой тип type_tab_AB является ассоциативным массивом, из-за INDEX BY BINARY_INTEGER предложения. Удалить INDEX BY BINARY_INTEGER пункт, чтобы сделать ваш type_tab_AB тип вложенной таблицы. (Varrays также будет работать здесь,но я бы не рекомендовал использовать их, если вы не знаете верхнюю границу для количества строк. При объявлении типа varray необходимо указать максимальное количество элементов, тогда как вложенные типы таблиц не имеют такого ограничения.)

после внесения этого изменения ваш код все равно может не работать. Следующая ошибка, которую вы можете получить (см. Примечание внизу, если вы этого не сделаете), -

PLS-00642: местная коллекция типы, не разрешенные в инструкциях SQL

это потому, что тип, который вы выбираете, объявлен внутри PL/SQL. Вам нужно объявить type_tab_AB и record_AB вне PL / SQL, используя CREATE TYPE ....

следующая проблема, которой вы столкнетесь, будет из-за ключевого слова RECORD. Типы записей могут быть созданы только внутри PL / SQL, они не могут быть созданы на уровне схемы. Изменить RECORD to OBJECT исправить.

последняя проблема вы столкнетесь с SELECT t.AA, t.BB BULK COLLECT INTO tab_AB FROM ... заявление. В его нынешнем виде этот запрос даст вам следующую ошибку:

PL / SQL: ORA-00947: недостаточно значений

вы выбираете два элемента из каждой строки и предоставляете только одну таблицу для массовой вставки данных. Oracle не может понять, что вы хотите вставить эти два элемента в свой record_AB тип. Вы можете исправить это довольно легко, изменив запрос SELECT record_AB(t.AA, t.BB) BULK COLLECT INTO tab_AB FROM ....

в совокупности эти изменения должны устранить проблему. Вот полный сценарий SQL * Plus, который создает тестовую таблицу с некоторыми тестовыми данными и проверяет, что он может запросить тип таблицы:

CREATE TABLE some_table (AA VARCHAR2(16 BYTE), BB VARCHAR2(16 BYTE));

INSERT INTO some_table (AA, BB) VALUES ('aa 1', 'bb 1');
INSERT INTO some_table (AA, BB) VALUES ('aaaaaaaaaa 2', 'b 2');
INSERT INTO some_table (AA, BB) VALUES ('aaaaa 3', 'bbbbbbbbbbbbbb 3');
COMMIT;

VARIABLE curs REFCURSOR;

CREATE OR REPLACE TYPE record_AB AS OBJECT
   (
      AA    VARCHAR2 (16 BYTE),
      BB    VARCHAR2 (16 BYTE)
   );
/

CREATE OR REPLACE TYPE type_tab_AB IS TABLE OF record_AB;
/

DECLARE
  tab_AB   type_tab_AB;
BEGIN
  SELECT record_AB(t.AA, t.BB)
    BULK COLLECT INTO tab_AB 
    FROM some_table t;

  OPEN :curs FOR SELECT * FROM TABLE (tab_AB) ;
END;
/

PRINT :curs

я поставил результат SELECTing содержание tab_AB в курсор и использовал переменную курсора SQL * Plus для отображения ее содержимого. Вывод, который я получаю, когда я запускаю скрипт на Oracle 11g XE, после того, как все процедуры "Type created" и " PL/SQL успешно завершенные сообщения, выглядит следующим образом:

AA               BB
---------------- ----------------
aa 1             bb 1
aaaaaaaaaa 2     b 2
aaaaa 3          bbbbbbbbbbbbbb 3

Примечание: для простоты я предположил, что спрашивающий использует Oracle 11 или старше. В Oracle 12 я считаю, что вам разрешено использовать типы, объявленные в PL / SQL в SQL-запросе, поэтому вы не можете столкнуться с ошибкой PLS-00642. Я не могу сказать, какие другие изменения в моем ответе также могут потребоваться для Oracle 12, поскольку я еще не использовал Oracle 12.


вы не можете запросить тип, созданный внутри блока pl/sql. Вам нужно создать его в SQL prompt, а затем вы можете запросить его. Смотрите пример ниже :

scott@ORA92> CREATE OR REPLACE TYPE emp_type AS OBJECT
  2    (id   NUMBER,
  3     name VARCHAR2(20));
  4  /

Type created.

scott@ORA92> CREATE OR REPLACE TYPE emp_tab AS TABLE OF emp_type;
  2  /

Type created.

scott@ORA92> VARIABLE g_ref REFCURSOR
scott@ORA92> DECLARE
  2    employees emp_tab := emp_tab();
  3  BEGIN
  4    employees.EXTEND(2);
  5    employees(1) := emp_type (1, 'name1');
  6    employees(2) := emp_type (2, 'name2');
  7    OPEN :g_ref FOR
  8    SELECT * FROM TABLE (CAST (employees AS emp_tab));
  9  END;
 10  /