Възможно е да се заявяват типове таблици в PL/SQL, но само вложени таблици и променливи, чиито типове са декларирани на ниво схема, т.е. извън PL/SQL.
Грешката
ORA-22905:няма достъп до редове от невложен елемент в таблица
означава, че се опитвате да правите заявка от неподдържан тип таблица. Вашият тип type_tab_AB
е асоциативен масив, поради INDEX BY BINARY_INTEGER
клауза. Премахнете INDEX BY BINARY_INTEGER
клауза, за да направите своя type_tab_AB
тип вложена таблица. (Променливите също биха работили тук, но не бих препоръчал да ги използвате, освен ако не знаете горна граница за броя на редовете, които да очаквате. Когато декларирате тип променлива, трябва да посочите максималния брой елементи, докато типовете вложени таблици имат няма такова ограничение.)
След като направите тази промяна, вашият код все още може да не работи. Следващата грешка, която може да получите (вижте бележката в долната част, ако не го направите), е
PLS-00642:типове локални колекции не са разрешени в SQL изрази
Това е така, защото типът, който избирате, е деклариран в PL/SQL. Трябва да декларирате type_tab_AB
и record_AB
извън PL/SQL, като използвате CREATE TYPE ...
.
Следващият проблем, който ще срещнете, ще бъде поради ключовата дума RECORD
. Типовете записи могат да се създават само в PL/SQL, не могат да се създават на ниво схема. Променете RECORD
към 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
Поставих резултата от SELECT
извеждане на съдържанието на tab_AB
в курсор и използва променлива на курсора SQL*Plus за изброяване на съдържанието му. Резултатът, който получавам, когато стартирам скрипта на Oracle 11g XE, след всички съобщения 'Type created' и 'PL/SQL procedure successfully completed', е както следва:
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.