Het is mogelijk om tabeltypen in PL/SQL op te vragen, maar alleen geneste tabellen en varrays waarvan de typen op schemaniveau zijn gedeclareerd, d.w.z. buiten PL/SQL.
De fout
ORA-22905:geen toegang tot rijen van een niet-genest tabelitem
betekent dat u een query probeert uit te voeren vanuit een niet-ondersteund tabeltype. Jouw type type_tab_AB
is een associatieve array, vanwege de INDEX BY BINARY_INTEGER
clausule. Verwijder de INDEX BY BINARY_INTEGER
clausule om uw type_tab_AB
een genest tabeltype. (Varrays zouden hier ook werken, maar ik zou het gebruik ervan niet aanbevelen, tenzij u een bovengrens kent voor het aantal te verwachten rijen. Wanneer u een varray-type declareert, moet u het maximale aantal elementen opgeven, terwijl geneste tabeltypen geen dergelijke beperking.)
Nadat u deze wijziging heeft aangebracht, werkt uw code mogelijk nog steeds niet. De volgende fout die u kunt krijgen (zie opmerking onderaan als u dat niet doet) is
PLS-00642:lokale verzamelingstypen niet toegestaan in SQL-instructies
Dit komt omdat het type waarin u selecteert, wordt gedeclareerd in PL/SQL. U moet type_tab_AB
. declareren , en record_AB
buiten PL/SQL, met behulp van CREATE TYPE ...
.
Het volgende probleem dat u tegenkomt, is het trefwoord RECORD
. Recordtypen kunnen alleen binnen PL/SQL worden gemaakt, ze kunnen niet op schemaniveau worden gemaakt. Wijzig RECORD
naar OBJECT
om dit op te lossen.
Het laatste probleem dat u tegenkomt is met de SELECT t.AA, t.BB BULK COLLECT INTO tab_AB FROM ...
uitspraak. Zoals het er nu uitziet, geeft deze query u de volgende foutmelding:
PL/SQL:ORA-00947:niet genoeg waarden
U selecteert twee items uit elke rij en biedt slechts één tabel om de gegevens in bulk in te voegen. Oracle kan er niet helemaal achter komen dat je de twee items in je record_AB
wilt stoppen type. U kunt dit vrij eenvoudig oplossen door de query te wijzigen in SELECT record_AB(t.AA, t.BB) BULK COLLECT INTO tab_AB FROM ...
.
Gezamenlijk zouden deze wijzigingen het probleem moeten oplossen. Hier is een volledig SQL*Plus-script dat een testtabel maakt met enkele testgegevens en controleert of het het tabeltype kan opvragen:
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
Ik heb het resultaat van SELECT
. geplaatst de inhoud van tab_AB
in een cursor en gebruikte een SQL*Plus-cursorvariabele om de inhoud ervan weer te geven. De uitvoer die ik krijg als ik het script op Oracle 11g XE uitvoer, na alle berichten 'Type aangemaakt' en 'PL/SQL-procedure succesvol voltooid', is als volgt:
AA BB
---------------- ----------------
aa 1 bb 1
aaaaaaaaaa 2 b 2
aaaaa 3 bbbbbbbbbbbbbb 3
OPMERKING: Voor de eenvoud heb ik aangenomen dat de vraagsteller Oracle 11 of ouder gebruikt. Ik geloof dat je in Oracle 12 typen mag gebruiken die zijn gedeclareerd in PL/SQL in een SQL-query, zodat je de PLS-00642-fout mogelijk niet tegenkomt. Ik kan niet zeggen welke andere wijzigingen in mijn antwoord ook nodig kunnen zijn voor Oracle 12, aangezien ik Oracle 12 nog moet gebruiken.