2013-10-06 14 views
7
DECLARE 
TYPE record_AB IS RECORD 
    (
     AA    VARCHAR2 (16 BYTE), 
     BB VARCHAR2 (16 BYTE) 
    ); 

    TYPE type_tab_AB IS TABLE OF record_AB 
         INDEX BY BINARY_INTEGER; 

    tab_AB type_tab_AB; 

    BEGIN 
    SELECT * 
    BULK COLLECT INTO tab_AB FROM... 
    .. 
    SELECT * FROM TABLE (tab_AB) ; 

Ottengo "ORA-22905: impossibile accedere alle righe da un elemento di tabella non annidato" quando arriva all'istruzione SELECT da TABLE.ORA-22905 - quando si esegue una query su un tipo di tabella con un'istruzione select

È anche possibile interrogare un tipo di tabella all'interno di PLSQL?

+0

Penso che questo abbia bisogno di più contesto. Puoi pubblicare un esempio minimo _complete_ che dimostra questo errore? Devi compilare 'tab_AB' con più record nella tua procedura affinché questo funzioni, in questo caso perché stai selezionando questa variabile. – Ben

risposta

23

E 'possibile interrogare tipi di tabella di PL/SQL, ma solo le tabelle nidificate e varrays i cui tipi sono dichiarati a livello di schema-, vale a dire al di fuori di PL/SQL.

L'errore

ORA-22905: cannot access rows from a non-nested table item

significa che si sta tentando di eseguire query da un tipo di tabella non supportato. Il tuo tipo type_tab_AB è un array associativo, a causa della clausola INDEX BY BINARY_INTEGER. Rimuovi la clausola INDEX BY BINARY_INTEGER per rendere il tuo type_tab_AB un tipo di tabella nidificato. (Anche i Varrays funzionerebbero qui, ma non consiglierei di usarli a meno che non si conosca un limite superiore per il numero di righe da aspettarsi.Quando si dichiara un tipo varray, è necessario specificare il numero massimo di elementi, mentre i tipi di tabella annidati hanno nessuna restrizione.)

Dopo aver apportato questa modifica, il codice potrebbe non funzionare. Il prossimo errore si può ottenere (vedi nota in fondo, se non) è

PLS-00642: local collection types not allowed in SQL statements

Questo perché il tipo si sta selezionando in è dichiarata all'interno PL/SQL. È necessario dichiarare type_tab_AB e record_AB al di fuori di PL/SQL, utilizzando CREATE TYPE ....

Il prossimo problema riscontrato sarà dovuto alla parola chiave RECORD. I tipi di record possono essere creati solo all'interno di PL/SQL, they cannot be created at schema level. Modificare RECORD a OBJECT per risolvere questo problema.

L'ultimo problema riscontrato è con la dichiarazione SELECT t.AA, t.BB BULK COLLECT INTO tab_AB FROM .... Così com'è, questa query vi darà il seguente errore:

PL/SQL: ORA-00947: not enough values

Si sta selezionando due elementi di ogni riga e stanno fornendo un solo tavolo di massa-inserire i dati in. Oracle non riesce a capire che vuoi inserire i due articoli nel tuo tipo record_AB. Puoi sistemarlo abbastanza facilmente cambiando la query in SELECT record_AB(t.AA, t.BB) BULK COLLECT INTO tab_AB FROM ....

Collettivamente queste modifiche dovrebbero risolvere il problema. Ecco uno SQL * completo più script che crea una tabella di test con alcuni dati di prova e verifica che si può interrogare il tipo di tabella:

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 

ho messo il risultato di SELECT ing i contenuti di tab_AB in un cursore, e ha utilizzato una variabile del cursore SQL * Plus per elencarne il contenuto.L'uscita ottengo quando faccio funzionare lo scritto su Oracle 11g XE, dopo tutte le 'Tipo creato' e 'procedure PL/SQL completata con successo' messaggi, è la seguente:

AA    BB 
---------------- ---------------- 
aa 1    bb 1 
aaaaaaaaaa 2  b 2 
aaaaa 3   bbbbbbbbbbbbbb 3 

NOTA: Per semplicità , Ho ipotizzato che l'interrogante stia usando Oracle 11 o precedente. In Oracle 12, credo che sia consentito utilizzare i tipi dichiarati in PL/SQL in una query SQL, quindi non si può incontrare l'errore PLS-00642. Non posso dire quali altre modifiche alla mia risposta potrebbero essere necessarie anche per Oracle 12 poiché non ho ancora utilizzato Oracle 12.

+1

'ma solo tabelle nidificate' Solo tabelle non nidificate. È anche possibile utilizzare l'operatore 'table' con i tipi di dati SQL di array di variabili. –

+1

@NicholasKrasnov: grazie, non lo sapevo. Ho aggiornato la mia risposta per menzionare i varrays. Non posso dire di aver usato i varrays prima, e non penso che funzionerebbero particolarmente bene qui. È un peccato che il messaggio di errore di Oracle implichi che solo le tabelle nidificate funzionano con l'operatore 'TABLE'. –

+0

Sto utilizzando entrambi gli oracle 12 e 11 e ho appena riscontrato questo errore nel porting dell'app da 12 a 11 cercando di selezionare dal tipo di tabella dichiarato a livello di specifica. Grazie! –

2

Non è possibile eseguire una query su un tipo creato all'interno di un blocco pl/sql. È necessario crearlo al prompt di SQL e quindi è possibile interrogarlo. Vedere exmaple di seguito:

[email protected]> CREATE OR REPLACE TYPE emp_type AS OBJECT 
    2 (id NUMBER, 
    3  name VARCHAR2(20)); 
    4/

Type created. 

[email protected]> CREATE OR REPLACE TYPE emp_tab AS TABLE OF emp_type; 
    2/

Type created. 

[email protected]> VARIABLE g_ref REFCURSOR 
[email protected]> DECLARE 
    2 employees emp_tab := emp_tab(); 
    3 BEGIN 
    4 employees.EXTEND(2); 
    5 employees(1) := emp_type (1, 'name1'); 
    6 employees(2) := emp_type (2, 'name2'); 
    7 OPEN :g_ref FOR 
    8 SELECT * FROM TABLE (CAST (employees AS emp_tab)); 
    9 END; 
10/
Problemi correlati