2012-09-13 19 views
13

tengo una matriz asociativa creado por un tipo de ROWTYPE de una columna de tabla.¿Por qué falla esta comprobación de matriz asociativa nula en PL/SQL?

Para dar un ejemplo, esto es lo que pasa (los nombres de las tablas son diferentes, pero la estructura es la misma):

Este es el DDL de la mesa

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

Aquí es lo que mi procedimiento está haciendo:

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; 

asumo debe resultado de "matriz asociativa nulo" que se está imprimiendo este . Sin embargo, la condición if falla y la ejecución salta a la parte else.

Ahora si pongo en un bucle for para imprimir los valores de la colección

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; 

continuación, la unidad de programa lanza una excepción, refiriéndose a la de línea de bucle

ORA-06502: PL/SQL : Error numérico o de valor

que supongo es debido a la matriz asociativa nula. ¿Se está produciendo el error debido a una matriz asociativa nula?

¿Por qué es el primer cheque fallando entonces? ¿Qué estoy haciendo mal?

El servidor de base de datos es Oracle 11g EE (versión 11.2.0.3.0 64 bits)

+0

No he hecho plsql desde hace tiempo, pero en su bucle ('dbms_output.put_line (nombre Emp: ' || Emp (i) .name); ') debe' Emp (i) .name' ser 'emp (i) .name'? –

+0

@jschoen los nombres de las variables no distinguen entre mayúsculas y minúsculas, por lo que no importa – Sathya

Respuesta

12

Asumo que esto debería resultar en un "array asociativo nulo" que se está imprimiendo. Esa suposición es incorrecta para las matrices asociativas. Existen cuando se declaran, pero están vacíos. Sería correcto para otros tipos de colecciones PL/SQL:

Hasta inicializar ella, una mesa de o anidada VARRAY es atómicamente nulo; la colección en sí es nula, no sus elementos. Para inicializar una tabla o VARRAY anidada, se utiliza un constructor, un función definida por el sistema con el mismo nombre que el tipo de colección. Esta función construye colecciones a partir de los elementos que se le pasan.

Debe llamar explícitamente un constructor para cada VARRAY y anidada variable de tabla.Conjuntos asociativos, el tercer tipo de colección, do no utiliza constructores. Las llamadas de constructor están permitidas siempre que se permitan las llamadas a la función . 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 

matriz de variables se hace correctamente:

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. 

Debido a que la matriz asociativa está vacía first y last son nulos, por lo que su segundo ejemplo produce 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 También tenga en cuenta que las matrices asociativas pueden ser dispersas. Al recorrer los números entre first y last se generará una excepción para cualquier colección que sea escasa. En su lugar utilizar first y next este modo: (Last y prev al bucle de la otra dirección.)

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

que lo deja claro. ¡Gracias por la respuesta detallada! – Sathya

+2

Esta es la respuesta correcta. Pero para mí, también resalta la rareza de Oracle a veces. Seguramente, el objetivo de una "matriz" de tamaño variable (o "tabla" en PLSQL-speak) es que usted no sabe de antemano cuántos registros tendrá en el momento de la ejecución (es decir, podría ser fácilmente cero). . ¡¡Y el objetivo de usar matrices es que puedas hacer bucles sobre ellas !! Por lo tanto, parece completamente contra-intuitivo tener que verificar que la lista tenga una longitud no nula antes de poder reproducirla. ¿Por qué no puede el analizador simplemente realizar ciclos cero, como ocurre en los cursores implícitos estándar? – cartbeforehorse

5

no voy a responder por qué el primer cheque está fallando. Nunca pensé en hacer algo así y estoy bastante sorprendido de que no genere un error.

La razón por la que está recibiendo una excepción planteada en el bucle es, como usted ha señalado, que el índice de emp.first no existe.

En lugar de la comprobación de valores nulos, que realmente debería estar mirando a la existencia de este índice. Lo que puede hacer que el uso de la sintaxis .exists(i):

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

Ben, la documentación de Oracle dice "No se puede usar EXISTS con una matriz asociativa". - http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/collections.htm#CJAEFFID habiendo dicho eso, la unidad del programa se ejecuta con éxito. Hrm. – Sathya

+0

Sí @Sathya, perdí el hecho de que lo estabas haciendo desde una fila de tablas. ¿Funciona con éxito? Me está fallando? Funcionará si este es el tipo de fila de un cursor. – Ben

+0

sí, como lo edité, por extraño que parezca, funciona correctamente a pesar de la documentación que dice lo contrario – Sathya

Cuestiones relacionadas