Det är möjligt att fråga tabelltyper i PL/SQL, men bara kapslade tabeller och varrayer vars typer deklareras på schemanivå, dvs utanför PL/SQL.
Felet
ORA-22905:kan inte komma åt rader från ett icke-kapslat tabellobjekt
betyder att du försöker fråga från en tabelltyp som inte stöds. Din typ type_tab_AB
är en associativ array, på grund av INDEX BY BINARY_INTEGER
klausul. Ta bort INDEX BY BINARY_INTEGER
sats för att göra din type_tab_AB
en kapslad tabelltyp. (Varrayer skulle också fungera här, men jag skulle inte rekommendera att använda dem om du inte vet en övre gräns för antalet rader som kan förväntas. När du deklarerar en varray-typ måste du ange det maximala antalet element, medan kapslade tabelltyper har ingen sådan begränsning.)
Efter att ha gjort denna ändring kanske din kod fortfarande inte fungerar. Nästa fel du kan få (se notering längst ner om du inte gör det) är
PLS-00642:lokala samlingstyper är inte tillåtna i SQL-satser
Detta beror på att typen du väljer deklareras i PL/SQL. Du måste deklarera type_tab_AB
och record_AB
utanför PL/SQL, med CREATE TYPE ...
.
Nästa problem du stöter på kommer att bero på nyckelordet RECORD
. Posttyper kan bara skapas i PL/SQL, de kan inte skapas på schemanivå. Ändra RECORD
till OBJECT
för att fixa detta.
Det sista problemet du kommer att stöta på är med SELECT t.AA, t.BB BULK COLLECT INTO tab_AB FROM ...
påstående. Som det ser ut kommer denna fråga att ge dig följande fel:
PL/SQL:ORA-00947:inte tillräckligt med värden
Du väljer två objekt från varje rad och tillhandahåller endast en tabell att massinsätta data i. Oracle kan inte riktigt lista ut att du vill stoppa in de två objekten i din record_AB
typ. Du kan rätta till detta ganska enkelt genom att ändra frågan till SELECT record_AB(t.AA, t.BB) BULK COLLECT INTO tab_AB FROM ...
.
Tillsammans borde dessa ändringar lösa problemet. Här är ett fullständigt SQL*Plus-skript som skapar en testtabell med vissa testdata och verifierar att den kan fråga efter tabelltypen:
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
Jag har lagt resultatet av SELECT
ing innehållet i tab_AB
till en markör och använde en SQL*Plus markörvariabel för att lista dess innehåll. Utdata som jag får när jag kör skriptet på Oracle 11g XE, efter alla meddelanden 'Typ skapad' och 'PL/SQL-proceduren har slutförts framgångsrikt', är följande:
AA BB
---------------- ----------------
aa 1 bb 1
aaaaaaaaaa 2 b 2
aaaaa 3 bbbbbbbbbbbbbb 3
OBS: För enkelhetens skull har jag antagit att frågeställaren använder Oracle 11 eller äldre. I Oracle 12 tror jag att du får använda typer som deklarerats i PL/SQL i en SQL-fråga, så du kanske inte stöter på PLS-00642-felet. Jag kan inte säga vilka andra ändringar i mitt svar som också kan vara nödvändiga för Oracle 12 eftersom jag ännu inte har använt Oracle 12.