Det er muligt at forespørge tabeltyper i PL/SQL, men kun indlejrede tabeller og varrays, hvis typer er erklæret på skemaniveau, dvs. uden for PL/SQL.
Fejlen
ORA-22905:kan ikke få adgang til rækker fra et ikke-indlejret tabelelement
betyder, at du forsøger at forespørge fra en ikke-understøttet tabeltype. Din type type_tab_AB
er en associativ matrix på grund af INDEX BY BINARY_INTEGER
klausul. Fjern INDEX BY BINARY_INTEGER
klausul for at lave din type_tab_AB
en indlejret tabeltype. (Varrays ville også fungere her, men jeg vil ikke anbefale at bruge dem, medmindre du kender en øvre grænse for antallet af rækker, du kan forvente. Når du erklærer en varray-type, skal du angive det maksimale antal elementer, hvorimod indlejrede tabeltyper har ingen sådan begrænsning.)
Når du har foretaget denne ændring, virker din kode muligvis stadig ikke. Den næste fejl du kan få (se note nederst, hvis du ikke gør det) er
PLS-00642:lokale samlingstyper er ikke tilladt i SQL-sætninger
Dette er fordi den type du vælger til er erklæret inde i PL/SQL. Du skal erklære type_tab_AB
, og record_AB
uden for PL/SQL ved hjælp af CREATE TYPE ...
.
Det næste problem, du støder på, vil være på grund af søgeordet RECORD
. Posttyper kan kun oprettes inde i PL/SQL, de kan ikke oprettes på skemaniveau. Skift RECORD
til OBJECT
for at rette dette.
Det sidste problem, du vil støde på, er med SELECT t.AA, t.BB BULK COLLECT INTO tab_AB FROM ...
udmelding. Som den står, vil denne forespørgsel give dig følgende fejl:
PL/SQL:ORA-00947:ikke nok værdier
Du vælger to elementer fra hver række og leverer kun én tabel til at masseindsætte dataene i. Oracle kan ikke helt finde ud af, at du vil proppe de to elementer ind i din record_AB
type. Du kan løse dette ret nemt ved at ændre forespørgslen til SELECT record_AB(t.AA, t.BB) BULK COLLECT INTO tab_AB FROM ...
.
Tilsammen burde disse ændringer løse problemet. Her er et komplet SQL*Plus-script, der opretter en testtabel med nogle testdata og verificerer, at den kan forespørge tabeltypen:
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
Jeg har lagt resultatet af SELECT
ing af indholdet af tab_AB
ind i en markør, og brugte en SQL*Plus-markørvariabel til at liste dens indhold. Outputtet, jeg får, når jeg kører scriptet på Oracle 11g XE, efter alle meddelelserne 'Type oprettet' og 'PL/SQL-procedure gennemført med succes', er som følger:
AA BB
---------------- ----------------
aa 1 bb 1
aaaaaaaaaa 2 b 2
aaaaa 3 bbbbbbbbbbbbbb 3
BEMÆRK: For nemheds skyld har jeg antaget, at spørgeren bruger Oracle 11 eller ældre. I Oracle 12 mener jeg, at du har tilladelse til at bruge typer erklæret i PL/SQL i en SQL-forespørgsel, så du kan ikke støde på PLS-00642-fejlen. Jeg kan ikke sige, hvilke andre ændringer af mit svar, der også kan være nødvendige for Oracle 12, da jeg endnu ikke har brugt Oracle 12.