Oracle
 sql >> Database >  >> RDS >> Oracle

ORA-22905 - quando si esegue una query su un tipo di tabella con un'istruzione select

È possibile eseguire query sui tipi di tabella in PL/SQL, ma solo su tabelle nidificate e varray i cui tipi sono dichiarati a livello di schema, ovvero al di fuori di PL/SQL.

L'errore

ORA-22905:impossibile accedere alle righe da un elemento della tabella non nidificato

significa che stai tentando di eseguire una query da un tipo di tabella non supportato. Il tuo tipo type_tab_AB è un array associativo, a causa di INDEX BY BINARY_INTEGER clausola. Rimuovi INDEX BY BINARY_INTEGER clausola per creare il tuo type_tab_AB un tipo di tabella nidificata. (Varray funzionerebbe anche qui, ma non consiglierei di usarli a meno che tu non 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 tabelle nidificate hanno nessuna restrizione del genere.)

Dopo aver apportato questa modifica, il codice potrebbe ancora non funzionare. Il prossimo errore che potresti ricevere (vedi nota in fondo se non lo fai) è

PLS-00642:tipi di raccolta locali non consentiti nelle istruzioni SQL

Questo perché il tipo in cui stai selezionando è dichiarato all'interno di PL/SQL. Devi dichiarare type_tab_AB e record_AB al di fuori di PL/SQL, utilizzando CREATE TYPE ... .

Il prossimo problema che incontrerai sarà a causa della parola chiave RECORD . I tipi di record possono essere creati solo all'interno di PL/SQL, non possono essere creati a livello di schema. Cambia RECORD a OBJECT per risolvere questo problema.

L'ultimo problema che incontrerai è con SELECT t.AA, t.BB BULK COLLECT INTO tab_AB FROM ... dichiarazione. Allo stato attuale, questa query ti darà il seguente errore:

PL/SQL:ORA-00947:valori insufficienti

Stai selezionando due elementi da ogni riga e stai fornendo solo una tabella in cui inserire i dati in blocco. Oracle non riesce a capire che vuoi inserire i due elementi nel tuo record_AB genere. Puoi risolverlo abbastanza facilmente modificando 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 script SQL*Plus completo che crea una tabella di test con alcuni dati di test e verifica che possa eseguire query sul 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 inserito il risultato di SELECT ing il contenuto di tab_AB in un cursore e ha utilizzato una variabile cursore SQL*Plus per elencarne il contenuto. L'output che ottengo quando eseguo lo script su Oracle 11g XE, dopo tutti i messaggi "Tipo creato" e "Procedura PL/SQL completata con successo", è il seguente:

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

NOTA: Per semplicità, ho ipotizzato che l'interrogante stia utilizzando Oracle 11 o versioni precedenti. In Oracle 12, credo che tu possa utilizzare i tipi dichiarati in PL/SQL in una query SQL, quindi potresti non riscontrare l'errore PLS-00642. Non posso dire quali altre modifiche alla mia risposta potrebbero essere necessarie anche per Oracle 12 poiché devo ancora utilizzare Oracle 12.