Możliwe jest odpytywanie typów tabel w PL/SQL, ale tylko tabele zagnieżdżone i zmienne, których typy są zadeklarowane na poziomie schematu, tj. poza PL/SQL.
Błąd
ORA-22905:brak dostępu do wierszy z niezagnieżdżonego elementu tabeli
oznacza, że próbujesz wykonać zapytanie z nieobsługiwanego typu tabeli. Twój typ type_tab_AB
jest tablicą asocjacyjną, ponieważ INDEX BY BINARY_INTEGER
klauzula. Usuń INDEX BY BINARY_INTEGER
klauzula, aby utworzyć type_tab_AB
zagnieżdżony typ tabeli. (Varrays również by tu działały, ale nie zalecałbym ich używania, chyba że znasz górną granicę liczby oczekiwanych wierszy. Deklarując typ varray, musisz określić maksymalną liczbę elementów, podczas gdy typy tabel zagnieżdżonych mają nie ma takiego ograniczenia.)
Po wprowadzeniu tej zmiany Twój kod może nadal nie działać. Następny błąd, który możesz otrzymać (patrz uwaga na dole, jeśli nie) to
PLS-00642:lokalne typy kolekcji nie są dozwolone w instrukcjach SQL
Dzieje się tak, ponieważ typ, który wybierasz, jest zadeklarowany w PL/SQL. Musisz zadeklarować type_tab_AB
i record_AB
poza PL/SQL, używając CREATE TYPE ...
.
Następny problem, który napotkasz, będzie spowodowany słowem kluczowym RECORD
. Typy rekordów można tworzyć tylko w PL/SQL, nie można ich tworzyć na poziomie schematu. Zmień RECORD
do OBJECT
by to naprawić.
Ostatni problem, jaki napotkasz, dotyczy SELECT t.AA, t.BB BULK COLLECT INTO tab_AB FROM ...
oświadczenie. W obecnej postaci to zapytanie spowoduje następujący błąd:
PL/SQL:ORA-00947:za mało wartości
Wybierasz dwa elementy z każdego wiersza i udostępniasz tylko jedną tabelę do zbiorczego wstawiania danych. Oracle nie może do końca zrozumieć, że chcesz umieścić te dwa elementy w swoim record_AB
rodzaj. Możesz to dość łatwo naprawić, zmieniając zapytanie na SELECT record_AB(t.AA, t.BB) BULK COLLECT INTO tab_AB FROM ...
.
Łącznie te zmiany powinny rozwiązać problem. Oto pełny skrypt SQL*Plus, który tworzy tabelę testową z niektórymi danymi testowymi i sprawdza, czy może wykonać zapytanie o typ tabeli:
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
Wstawiłem wynik SELECT
zawartość tab_AB
do kursora i użył zmiennej kursora SQL*Plus, aby wyświetlić jego zawartość. Dane wyjściowe, które otrzymuję po uruchomieniu skryptu w Oracle 11g XE, po wszystkich komunikatach „Typ utworzony” i „Procedura PL/SQL pomyślnie zakończona”, są następujące:
AA BB
---------------- ----------------
aa 1 bb 1
aaaaaaaaaa 2 b 2
aaaaa 3 bbbbbbbbbbbbbb 3
UWAGA: Dla uproszczenia założyłem, że pytający używa Oracle 11 lub starszego. Uważam, że w Oracle 12 możesz używać typów zadeklarowanych w PL/SQL w zapytaniu SQL, więc możesz nie napotkać błędu PLS-00642. Nie mogę powiedzieć, jakie inne zmiany w mojej odpowiedzi mogą być również konieczne dla Oracle 12, ponieważ jeszcze nie korzystam z Oracle 12.