2012-09-13 10 views
13

Ho una matrice associativa creata da un tipo di rowtype di una colonna di tabella.Perché questo controllo per array associativo nullo in PL/SQL non riesce?

Per fare un esempio, questo è come è (i nomi delle tabelle sono diversi, ma la struttura è la stessa):

Questo è il DDL del tavolo

CREATE TABLE employees 
    (
    id  NUMBER, 
    name VARCHAR2(240), 
    salary NUMBER 
); 

Ecco ciò che il mio procedura sta facendo:

DECLARE 
    TYPE table_of_emp 
     IS TABLE OF employees%ROWTYPE INDEX BY BINARY_INTEGER; 
    emp TABLE_OF_EMP; 
BEGIN 
    IF emp IS NULL THEN 
     dbms_output.Put_line('Null associative array'); 
    ELSE 
     dbms_output.Put_line('Not null'); 
    END IF; 
END; 

presumo che ciò dovrebbe risultato in "array associativo Null" in fase di stampa. Tuttavia, la condizione if non riesce e l'esecuzione salta alla parte else.

Ora, se ho messo in un ciclo for per stampare i valori della collezione

DECLARE 
    TYPE table_of_emp 
     IS TABLE OF employees%ROWTYPE INDEX BY BINARY_INTEGER; 
    emp TABLE_OF_EMP; 
BEGIN 
    IF emp IS NULL THEN 
     dbms_output.Put_line('Null associative array'); 
    ELSE 
     dbms_output.Put_line('Not null'); 

     FOR i IN emp.first..emp.last LOOP 
      dbms_output.Put_line('Emp name: ' 
           || Emp(i).name); 
     END LOOP; 
    END IF; 
END; 

allora l'unità del programma solleva un'eccezione, facendo riferimento il ciclo for linea di

ORA-06502: PL/SQL : Errore numerico o valore

che presumo sia dovuto alla matrice associativa nulla. L'errore viene generato a causa dell'array associativo nullo?

Quindi perché il primo controllo non è riuscito? Che cosa sto facendo di sbagliato?

Il server di database è Oracle 11g EE (versione 11.2.0.3.0 64 bit)

+0

non ho fatto plsql in un po ', ma nel tuo ciclo for ('dbms_output.put_line ('nome Emp:' || Emp (i) .name); ') dovrebbe' Emp (i) .name' essere 'emp (i) .name'? –

+0

I nomi delle variabili @jschoen non fanno distinzione tra maiuscole e minuscole, quindi non importa – Sathya

risposta

12

Presumo che ciò dovrebbe tradursi in "array associativo Null" in fase di stampa. Questa ipotesi è errata per gli array associativi. Esistono quando dichiarati, ma sono vuoti. Sarebbe corretto per gli altri tipi di collezioni PL/SQL:

Fino a quando si inizializza esso, un tavolo o nidificato varray è atomicamente null; la raccolta stessa è nullo, non i suoi elementi. Per inizializzare una tabella nidificata o varray , si utilizza una funzione di costruzione, una funzione definita dal sistema con lo stesso nome del tipo di raccolta. Questa funzione costruisce collezioni dagli elementi passati ad essa.

È necessario chiamare esplicitamente un costruttore per ogni variabile di tabella nidificata.Gli array associativi, il terzo tipo di raccolta, fanno non utilizzare i costruttori. Le chiamate al costruttore sono consentite ovunque siano consentite le chiamate . Initializing and Referencing Collections

Compare:

SQL> declare 
    2  type varchar2_100_aa is table of varchar2(100) index by binary_integer; 
    3  test varchar2_100_aa; 
    4 begin 
    5  test(1) := 'Hello'; 
    6  dbms_output.put_line(test(1)); 
    7 end; 
    8/
Hello 

PL/SQL procedure successfully completed. 

SQL> declare 
    2  type varchar2_100_va is varray(100) of varchar2(100); 
    3  test varchar2_100_va; 
    4 begin 
    5  test(1) := 'Hello'; 
    6  dbms_output.put_line(test(1)); 
    7 end; 
    8/
declare 
* 
ERROR at line 1: 
ORA-06531: Reference to uninitialized collection 
ORA-06512: at line 5 

matrice variabile eseguito correttamente:

SQL> declare 
    2  type varchar2_100_va is varray(10) of varchar2(100); 
    3  test varchar2_100_va; 
    4 begin 
    5  test := varchar2_100_va(); -- not needed on associative array 
    6  test.extend; -- not needed on associative array 
    7  test(1) := 'Hello'; 
    8  dbms_output.put_line(test(1)); 
    9 end; 
10/
Hello 

PL/SQL procedure successfully completed. 

Poiché l'array associativo è vuoto first e last sono nulli, ragion per cui il secondo esempio risultati in ORA-06502: PL/SQL: Numeric or value error:

SQL> declare 
    2  type varchar2_100_aa is table of varchar2(100) index by binary_integer; 
    3  test varchar2_100_aa; 
    4 begin 
    5  dbms_output.put_line(test.count); 
    6  dbms_output.put_line(coalesce(to_char(test.first), 'NULL')); 
    7  dbms_output.put_line(coalesce(to_char(test.last), 'NULL')); 
    8  test(1) := 'Hello'; 
    9  dbms_output.new_line; 
10  dbms_output.put_line(test.count); 
11  dbms_output.put_line(coalesce(to_char(test.first), 'NULL')); 
12  dbms_output.put_line(coalesce(to_char(test.last), 'NULL')); 
13 end; 
14/
0 
NULL 
NULL 

1 
1 
1 

PL/SQL procedure successfully completed. 

EDIT Si noti inoltre che gli array associativi possono essere sparsi. La ripetizione dei numeri tra first e last genererà un'eccezione per qualsiasi raccolta sparsa. Invece utilizzare first e next in questo modo: (Last e prev ad anello nella direzione opposta.)

SQL> declare 
    2  type varchar2_100_aa is table of varchar2(100) index by binary_integer; 
    3  test varchar2_100_aa; 
    4  i binary_integer; 
    5 begin 
    6  test(1) := 'Hello'; 
    7  test(100) := 'Good bye'; 
    8  dbms_output.put_line(test.count); 
    9  dbms_output.put_line(coalesce(to_char(test.first), 'NULL')); 
10  dbms_output.put_line(coalesce(to_char(test.last), 'NULL')); 
11  dbms_output.new_line; 
12 -- 
13  i := test.first; 
14  while (i is not null) loop 
15   dbms_output.put_line(to_char(i, '999') || ' - ' || test(i)); 
16   i := test.next(i); 
17  end loop; 
18 end; 
19/
2 
1 
100 

    1 - Hello 
100 - Good bye 

PL/SQL procedure successfully completed. 
+0

che lo rende chiaro. Grazie per la risposta dettagliata! – Sathya

+2

Questa è la risposta corretta. Ma per me, mette in evidenza anche la stranezza di Oracle a volte. Sicuramente l'intero punto di un "array" di dimensioni variabili (o "table" in PLSQL-speak) è che non sai in anticipo quanti record avrai al momento dell'esecuzione (cioè potrebbe essere facilmente zero) . E il punto fondamentale di usare gli array è che puoi looparli su di loro !!. Sembra quindi completamente contro-intuitivo dover controllare che l'elenco abbia una lunghezza diversa da zero prima di poterlo fare in loop. Perché il parser non può semplicemente eseguire cicli zero volte, come nei cursori impliciti standard? – cartbeforehorse

5

io non ho intenzione di rispondere perché il primo controllo sta fallendo. Non ho mai pensato di fare qualcosa del genere e sono abbastanza sorpreso dal fatto che non genera un errore.

Il motivo per cui stai ricevendo un'eccezione generata nel ciclo è, come hai notato, che l'indice emp.first non esiste.

Invece di controllare i valori null, è necessario verificare l'esistenza di questo indice. Che si può fare essere utilizzando la sintassi .exists(i):

if not emp.exists(emp.first) then 
    dbms_output.put_line('Nothing in here.'); 
end if; 
+0

Ben, la documentazione Oracle dice "Non è possibile utilizzare EXISTS con un array associativo". - http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/collections.htm#CJAEFFID detto questo, l'unità di programma viene eseguita correttamente. Hrm. – Sathya

+0

Sì @Sathya, mi è dispiaciuto il fatto che lo stavate facendo da un tipo di riga tabella. Funziona con successo? Sta fallendo per me? Funzionerà se questo è il tipo di riga di un cursore. – Ben

+0

sì, come ho modificato, stranamente funziona con successo nonostante la documentazione che dice altrimenti – Sathya

Problemi correlati