3.2.- Colecciones. Arrays de longitud variable.
Una colección es un grupo ordenado de elementos, todos del mismo tipo. Cada elemento tiene un subíndice único que determina su posición en la colección.
En PL/SQL las colecciones sólo pueden tener una dimensión. PL/SQL ofrece 2 clases de colecciones: arrays de longitud variable y tablas anidadas.
Arrays de longitud variable.
Los elementos del tipo VARRAY
son los llamados arrays de longitud variable. Son como los arrays de cualquier otro lenguaje de programación, pero con la salvedad de que a la hora de declararlos, nosotros indicamos su tamaño máximo y el array podrá ir creciendo dinámicamente hasta alcanzar ese tamaño. Un VARRAY
siempre tiene un límite inferior igual a 1 y un límite superior igual al tamaño máximo.
Para declarar un VARRAY
usaremos la sintaxis:
TYPE nombre IS {VARRAY | VARYING} (tamaño_máximo) OF tipo_elementos [NOT NULL];
Donde tamaño_máximo
será un entero positivo y tipo_elementos
será cualquier tipo de dato válido en PL/SQL, excepto BINARY_INTEGER
, BOOLEAN
, LONG
, LONG RAW
, NATURAL
, NATURALN
, NCHAR
, NCLOB
, NVARCHAR2
, objetos que tengan como atributos TABLE
o VARRAY
, PLS_INTEGER
, POSITIVE
, POSITIVEN
, SIGNTYPE
, STRING
, TABLE
, VARRAY
. Si tipo_elementos
es un registro, todos los campos deberían ser de un tipo escalar.
Cuando definimos un VARRAY
, éste es automáticamente nulo, por lo que para empezar a utilizarlo deberemos inicializarlo. Para ello podemos usar un constructor:
TYPE familias_hijas IS VARRAY(100) OF familia;
familias_hijas1 familias_hijas := familias_hijas( familia(100, ’Fam100’, 10, null), ..., familia(105, ’Fam105’, 10, null));
También podemos usar constructores vacíos.
familias_hijas2 familias_hijas := familias_hijas();
Para referenciar elementos en un VARRAY
utilizaremos la sintaxis nombre_colección(subíndice)
. Si una función devuelve un VARRAY
, podemos usar la sintaxis: nombre_funcion(lista_parametros)(subindice)
.
IF familias_hijas1(i).identificador = 100 THEN ...
IF dame_familias_hijas(10)(i).identificador = 100 THEN ...
Un VARRAY
puede ser asignado a otro si ambos son del mismo tipo.
DECLARE
TYPE tabla1 IS VARRAY(10) OF NUMBER;
TYPE tabla2 IS VARRAY(10) OF NUMBER;
mi_tabla1 tabla1 := tabla1();
mi_tabla2 tabla2 := tabla2();
mi_tabla tabla1 := tabla1();
BEGIN
...
mi_tabla := mi_tabla1; --legal
mi_tabla1 := mi_tabla2; --ilegal
...
END;
Para extender un VARRAY
usaremos el método EXTEND
. Sin parámetros, extendemos en 1 elemento nulo el VARRAY
. EXTEND(n)
añade n elementos nulos al VARRAY
y EXTEND(n,i)
añade n copias del i-ésimo elemento.
COUNT
nos dirá el número de elementos del VARRAY
. LIMIT
nos dice el tamaño máximo del VARRAY. FIRST
siempre será 1. LAST
siempre será igual a COUNT
. PRIOR
y NEXT
devolverá el antecesor y el sucesor del elemento.
Al trabajar con VARRAY
podemos hacer que salte alguna de las siguientes excepciones, debidas a un mal uso de los mismos: COLECTION_IS_NULL
, SUBSCRIPT_BEYOND_COUNT
, SUBSCRIPT_OUTSIDE_LIMIT
y VALUE_ERROR
.
Ejemplos de uso de los VARRAY
.
- Extender un
VARRAY
.
DECLARE
TYPE tab_num IS VARRAY(10) OF NUMBER;
mi_tab tab_num;
BEGIN
mi_tab := tab_num();
FOR i IN 1..10 LOOP
mi_tab.EXTEND;
mi_tab(i) := calcular_elemento(i);
END LOOP;
...
END;
- Consultar propiedades
VARRAY
.
DECLARE
TYPE numeros IS VARRAY(20) OF NUMBER;
tabla_numeros numeros := numeros();
num NUMBER;
BEGIN
num := tabla_numeros.COUNT; --num := 0
FOR i IN 1..10 LOOP
tabla_numeros.EXTEND;
tabla_numeros(i) := i;
END LOOP;
num := tabla_numeros.COUNT; --num := 10
num := tabla_numeros.LIMIT; --num := 20
num := tabla_numeros.FIRST; --num := 1;
num := tabla_numeros.LAST; --num := 10;
...
END;
- Posibles excepciones.
DECLARE
TYPE numeros IS VARRAY(20) OF INTEGER;
v_numeros numeros := numeros( 10, 20, 30, 40 );
v_enteros numeros;
BEGIN
v_enteros(1) := 15; --lanzaría COLECTION_IS_NULL
v_numeros(5) := 20; --lanzaría SUBSCRIPT_BEYOND_COUNT
v_numeros(-1) := 5; --lanzaría SUBSCRIPT_OUTSIDE_LIMIT v_numeros(‘A’) := 25; --
lanzaría VALUE_ERROR
....
END;
Los constructores son funciones o métodos cuyo nombre es igual al nombre de su objeto. Se utilizan para inicializar un objeto. En la mayoría de los casos, esta inicialización asigna valores a los miembros del objeto.