Objetivos:
• Describir los records y collections de PL/SQL.
• Describir los records y collections de PL/SQL.
• Crear records definidos por el usuario.
• Crear un record con el atributo %ROWTYPE.
• Crear matrices asociativas(associative arrays):
--INDEX BY table.
--INDEX BY table of records.
• Crear un record con el atributo %ROWTYPE.
• Crear matrices asociativas(associative arrays):
--INDEX BY table.
--INDEX BY table of records.
NOTA: Usamos como ejemplo la Base de Datos: ORCL, la cual viene por defecto en cualquier versión de ORACLE.
____________________________________________________________________________________
Tipos de Datos Compuestos.
Tipos de Datos Compuestos.
Las variables escalares pueden contener sólo un valor, mientras que las variables de tipo de dato compuesto pueden contener varios valores de tipo de dato escalar o el tipo de dato compuesto. Los dos tipos de tipos de datos compuestos disponibles en PL/SQL son:
• PL/SQL Records: Los Records se utilizan para tratar como una unidad lógica tipos de datos distintos que guardan relación. Un Records de PL/SQL puede tener variables de diferentes tipos. Por ejemplo, puede definir un Record para contener detalles de empleados. Esto implica el almacenamiento de un número de empleado como NUMBER, un nombre y un apellido como VARCHAR2, y así sucesivamente. Mediante la creación de un Record para almacenar detalles de empleados, se crea una unidad lógica colectiva. Esto hace más fácil el acceso y la manipulación de los datos.
• PL/SQL Collections: Las Colecciones se utilizan para tratar datos como una sola unidad. Las colecciones son de tres tipos:
--Associative array.--Nested table.
--VARRAY.
¿Por qué usar de datos compuestos?
Usted tiene todos los datos relacionados como una sola unidad. Puede acceder y modificar fácilmente los datos. Si están compuesto, los datos resultan más fáciles de manejar, relacionar, y el transportar. Una analogía es tener solo una bolsa para todos los componentes de su computadora portátil en lugar de una bolsa separada para cada componente.
Si los Records y Colecciones de PL/SQL son ambos tipos de datos compuestos, ¿Cómo elegir cuál usar?
• Utilice Records cuando se desea almacenar valores de diferentes tipos de datos que están relacionados lógicamente. Por ejemplo, puede crear un Record para contener detalles de empleados y indicar que todos los valores almacenados están relacionados, ya que proporcionan información sobre un empleado en particular.
• Utilice Colecciones cuando se desea almacenar valores del mismo tipo de dato. Tenga en cuenta que este tipo de dato también puede ser de tipo compuesto (por ejemplo, Records). Se puede definir una colección para almacenar el primer nombre de todos los empleados. Puede que haya guardado n nombres en la colección; Sin embargo, el nombre 1 no está relacionado con el nombre 2. La única relación posible es que son nombres de los empleados. Estas colecciones son similares a las matrices en lenguajes de programación como C, C++ y Java.
____________________________________________________________________________________
Records de PL/SQL.
Records de PL/SQL.
Los Records de PL/SQL:
• Deben contener uno o más componentes (llamados campos) de cualquier tipo: escalar, Record o INDEX BY table.
• Son similares a las estructuras de la mayoría de lenguajes de tercera generación (incluyendo C y C ++).
• Son definidos por el usuario y pueden ser un subconjunto de una fila de una tabla.
• Trata una colección de campos como una unidad lógica.
• Son convenientes para extraer una fila de datos de una tabla para su procesamiento.
Un Record es un grupo de elementos de datos relacionados almacenados en campos, cada campo con su propio nombre y tipo de dato:
• Cada Record puede tener tantos campos como sea necesario.
• A los Records se les puede asignar valores iniciales y pueden definirse como NOT NULL.
• A los campos sin valores iniciales son inicializados con NULL.
• La palabra clave DEFAULT, así como := se pueden utilizar en la inicialización de campos.
• Se pueden definir tipos(types) de Records y declarar Records definidos por el usuario en la parte declarativa de cualquier bloque, subprograma o paquete.
• Se puede declarar y hacer referencia a los Records anidados. Un Record puede ser un componente de otro Record.
Sintaxis:
TYPE type_name IS RECORD
(
field_declaration[,
field_declaration]…
);
--
field_declaration:
field_name {field_type | variable%TYPE
| table.column%TYPE | table%ROWTYPE}
[[NOT NULL] {:= | DEFAULT} expr]
--
identifier type_name;
En la sintaxis:
type_name
|
Es el nombre del tipo Record (Este identificador se utiliza para
declarar las variables tipo Records).
|
field_name
|
Es el nombre de un campo dentro
del Record.
|
field_type
|
Es el
tipo de dato del campo (Representa cualquier tipo de dato PL/SQL excepto REF
CURSOR. Puede utilizar los atributos %ROWTYPE y %TYPE).
|
expr
|
Es el
valor inicial.
|
La restricción NOT NULL impide la asignación de valores nulos en los campos especificados. Asegúrese de inicializar los campos NOT NULL.
Ejemplo:
DECLARETYPE client_typ_rec IS RECORD
(
codigo NUMBER(6),
nombre VARCHAR2(35),
direccion VARCHAR2(50),
telefono VARCHAR2(10),
fec_ingreso DATE
);
--
v_cliente client_typ_rec;
BEGIN
v_cliente.codigo := 1;
v_cliente.nombre := 'Julio Aponte';
v_cliente.fec_ingreso := SYSDATE;
END;
/*En el ejemplo se crea un tipo record: client_typ_rec, luego se crea una variable(v_cliente) de ese tipo record y posteriormente se le asigna valores a los campos de la variable en la sección ejecutable del bloque.*/
____________________________________________________________________________________
Atributo %ROWTYPE.
Ya vimos que %TYPE se utiliza para declarar una variable de tipo columna. Dicha variable tiene el mismo tipo de dato y tamaño que la columna de la tabla. El beneficio de %TYPE es que usted no tiene que cambiar la variable si se altera la columna. Además, si la variable es un número y se utiliza en los cálculos, usted no necesita preocuparse acerca de su precisión.
El atributo %ROWTYPE se utiliza para declarar un Record que contenga toda la fila de una tabla o vista. Los campos en el Record toman los nombres y tipos de datos de las columnas de la tabla o vista. El Record también puede almacenar toda una fila de datos obtenida de un cursor o variable de cursor.
Sintaxis:
DECLARE
identifier reference%ROWTYPE;
En la Sintaxis:
identifier
|
Es el nombre de la variable tipo record. |
reference
|
Es el nombre de la tabla, vista, cursor, o variable de cursor en el cual se basa la variable record (Para que la referencia sea validad, la tabla o vista debe existir). |
DECLARE
v_rec_empleado employees%ROWTYPE;
....
El Record v_rec_empleado tiene una estructura que consta de los siguientes campos, cada uno representando una columna en la tabla empleados.
(
employee_id NUMBER(6),
first_name VARCHAR2(20),
last_name VARCHAR2(20),
email VARCHAR2(20),
phone_number VARCHAR2(20),
hire_date DATE,
salary NUMBER(8,2),
commission_pct NUMBER(2,2),
manager_id NUMBER(6),
department_id NUMBER(4)
)
Asignando valores a los Records.
Puede asignar una lista de valores comunes a un registro utilizando la sentencias SELECT o FETCH. Asegúrese de que los nombres de columna aparezcan en el mismo orden que los campos en su Record. También puede asignar un Record a otro, si ambos tienen los mismos tipos de datos. Un Record de tipo employees%ROWTYPE y un tipo Record definido por el usuario con campos análogos de la tabla employees tendrán los mismos tipos de datos. Por lo tanto, si un Record definido por el usuario contiene campos similares a los de un Record %ROWTYPE, sera posible asignar ese Record definido por el usuario a el Record %ROWTYPE.
Las declaraciones de campos utilizados en la definición de un Record son como las declaraciones de variables. Cada campo tiene un nombre único y un tipo de datos específico. No hay tipos de datos predefinidos para los Records de PL/SQL, como en el caso de las variables escalares. Por lo tanto, se requiere crear el tipo Record en primer lugar, y luego declarar un identificador usando ese tipo.
Ejemplo:
SET SERVEROUTPUT ON
DECLARE
TYPE t_rec IS RECORD
(
v_sal NUMBER(8),
v_minsal NUMBER(8) DEFAULT 1000,
v_fecha_contrato employees.hire_date%TYPE,
v_rec1 employees%ROWTYPE
);
---
v_mirec t_rec;
BEGIN
v_mirec.v_sal := v_mirec.v_minsal + 500;
v_mirec.v_fecha_contrato := SYSDATE;
---
SELECT * INTO v_mirec.v_rec1
FROM employees
WHERE employee_id = 100;
---
DBMS_OUTPUT.PUT_LINE(v_mirec.v_rec1.last_name
||' '||to_char(v_mirec.v_fecha_contrato)
||' '|| to_char(v_mirec.v_sal));
END;
---
En el ejemplo, un Record de PL/SQL se crea utilizando los dos pasos necesarios:
1. Se define un tipo Record (t_rec).
2. Se declara un Record (v_mirec) del tipo t_rec.
Nota:
• El Record contiene cuatro campos: v_sal, v_minsal, v_fecha_contrato, y v_rec1.
• v_rec1 se define mediante el atributo %ROWTYPE, que es similar al atributo %TYPE. Con %TYPE, un campo hereda el tipo de dato de una columna especificada. Con %ROWTYPE, el campo hereda los nombres y tipos de datos de todas las columnas de la tabla referenciada.
• Los campos de un Record de PL/SQL se pueden referenciar mediante la notación <Record>.<campo>, o con <Record>.<campo>.<columna> para los campos que se definen con el atributo %ROWTYPE.
• Puede añadir la restricción NOT NULL a cualquier declaración de campo para evitar la asignación de valores nulos a ese campo. Recuerde que los campos declarados como NOT NULL deben inicializarse.
Ventajas del Atributo %ROWTYPE.
• No es necesario conocer el número y tipos de datos de las columnas de Base de Datos y, de hecho, dichas columnas podrían cambiar en tiempo de ejecución sin afectar el Record.
• El atributo %ROWTYPE es útil cuando se desea recuperar una fila con:
--La instrucción SELECT *
--Sentencias INSERT y UPDATE a nivel de fila.
Utilice el atributo %ROWTYPE cuando no está seguro acerca de la estructura de la tabla de Base de Datos subyacente.
La principal ventaja de utilizar %ROWTYPE es que simplifica el mantenimiento. Usando %ROWTYPE asegura que los tipos de datos de las variables declaradas con este atributo cambian dinámicamente cuando se altera la tabla subyacente. Si una instrucción DDL cambia las columnas de una tabla, el programa PL/SQL se invalida. Cuando se vuelve a compilar el programa, se refleja automáticamente el nuevo formato de tabla.
El atributo %ROWTYPE es particularmente útil cuando se desea recuperar toda una fila de una tabla. En ausencia de este atributo, se verá forzado a declarar una variable para cada columna devuelta por la sentencia SELECT.
Ejemplos:
CREATE TABLE emps_retirados
(
codigo NUMBER(4),
nombre VARCHAR2(10),
empleo VARCHAR2(9),
manager NUMBER(4),
fec_entrada DATE,
fec_salida DATE,
salario NUMBER(7,2),
comision NUMBER(7,2),
departameto NUMBER(2)
);
/*Creamos esta tabla que nos servirá de ejemplo.*/
---
DECLARE
v_codigo_emp NUMBER := 124;
v_emp_rec emps_retirados%ROWTYPE;
BEGIN
SELECT
employee_id,
last_name,
job_id,
manager_id,
hire_date,
SYSDATE,
salary,
commission_pct,
department_id
INTO v_emp_rec
FROM employees
WHERE employee_id = v_codigo_emp;
---
INSERT INTO emps_retirados
VALUES v_emp_rec;
---
COMMIT;
END;
/
SELECT *
FROM emps_retirados;
/*Este SCRIPT recupera los datos del empleado 124 de la tabla employees y luego los inserta en la tabla emps_retirados; notar como se simplifica la sentencia INSERT con el uso del atributo %ROWTYPE.*/
---OUTPUT:
DECLARE
v_codigo_emp NUMBER := 124;
v_emp_rec emps_retirados%ROWTYPE;
BEGIN
SELECT * INTO v_emp_rec
FROM emps_retirados
WHERE codigo = v_codigo_emp;
---
v_emp_rec.nombre := 'Samira';
v_emp_rec.empleo := 'Secre';
v_emp_rec.fec_salida := SYSDATE-2;
---
UPDATE emps_retirados
SET ROW = v_emp_rec
WHERE codigo = v_codigo_emp;
---
COMMIT;
END;
/
SELECT *
FROM emps_retirados;
/*En este se recuperan los datos del mismo empleado 124 pero ahora de la tabla emps_retirados, luego se les hace algunas modificaciones a los datos y luego se actualiza el registro en la misma tabla; notar que simple luce la sentencia UPDATE con el uso del atributo %ROWTYPE.*/
____________________________________________________________________________________
Colecciones de PL/SQL.
Como se dijo anteriormente, se usan colecciones de PL/SQL cuando se desea almacenar valores del mismo tipo de datos. Este tipo de datos puede ser también de tipo compuesto (por ejemplo, Records).
Por lo tanto, las colecciones se usan para tratar los datos como una sola unidad. Las colecciones son de tres tipos:
• Associative Array O Matriz Asociativa.
• Nested Table.
• VARRAY.
Associative Array(INDEX BY tables).
Un Associative Array es un tipo de colección de PL/SQL, es un tipo de datos compuesto, y es definido por el usuario. Este tipo esta compuesto por conjuntos de pares key-value, entiéndase key como la llave primaria y value como el valor de la fila. Pueden almacenar datos utilizando una llave primaria(key) como el índice, donde la llave primaria no necesariamente tiene que ser secuencial. Los Associative Arrays son también conocidos como INDEX BY tables.
Los Associative Array tienen sólo dos columnas, a las cuales no es posible asignarles nombres:
• La primera columna, de tipo entero o carácter, actúa como la llave primaria.
• La segunda columna, de tipo escalar o Record, contiene los valores.
Ejemplo:
Estructura de los Associative Arrays.
Como se mencionó anteriormente, los Associative Arrays tienen dos columnas. La segunda columna puede contener un valor por cada fila, o varios valores.
Llave primaria única: El tipo de dato de esta columna puede ser:
• Numérico, ya sea BINARY_INTEGER o PLS_INTEGER. Estos dos tipos de datos numéricos requieren menos almacenamiento que los NUMBER, y las operaciones aritméticas sobre ellos son más rápidas que con NUMBER.
• VARCHAR2 o uno de sus subtipos.
Columna "Value": La columna Value puede ser de tipo de dato escalar o tipo de dato Record. Una columna con tipo de dato escalar sólo puede tener un valor por fila, mientras que una columna con tipo de dato Record puede contener varios valores por fila.
Otras características.
• Un Associative Array no se rellena en el momento de la declaración. No contiene llaves primarias o valores, y no se puede inicializar al momento de su declaración.
• Se requiere una sentencias ejecutable explícita para rellenar el Associative Array.
• Al igual que el tamaño de una tabla de Base de Datos, el tamaño de un Associative Array no tiene restricciones. Es decir, el número de filas puede aumentar de forma dinámica para que su Associative Array crezca a medida que se añaden nuevas filas. Tenga en cuenta que las llaves primarias no tienen que ser secuenciales, y pueden ser tanto positiva como negativa.
Sintaxis:
TYPE type_name IS TABLE OF
{ column_type [NOT NULL] | variable%TYPE [NOT NULL]
| table.column%TYPE [NOT NULL]
| table%ROWTYPE }
INDEX BY { PLS_INTEGER | BINARY_INTEGER
| VARCHAR2(<size>) } ;
identifier type_name;
Ejemplo:
SET SERVEROUTPUT ON
DECLARE
TYPE nombre_tab_typ
IS TABLE OF employees.last_name%TYPE
INDEX BY PLS_INTEGER;
TYPE fec_contrato_tab_typ
IS TABLE OF DATE
INDEX BY PLS_INTEGER;
t_nombre nombre_tab_typ;
t_fec_contrato fec_contrato_tab_typ;
BEGIN
t_nombre(1) := 'Pepe';
t_fec_contrato(1) := SYSDATE;
--
SELECT last_name,
hire_date
INTO t_nombre(6),
t_fec_contrato(6)
FROM employees
WHERE employee_id = 111;
--
FOR i IN t_nombre.FIRST..t_nombre.LAST LOOP
IF t_nombre.EXISTS(i) THEN
DBMS_OUTPUT.PUT_LINE(i||'. Nombre: '||t_nombre(i)||', Fecha: '||t_fec_contrato(i));
ELSE
DBMS_OUTPUT.PUT_LINE('Indice: '||i||' no asignado');
END IF;
END LOOP;
END;
/*En este ejemplo creamos un tipo tabla de nombres: nombre_tab_typ y un tipo tabla de fechas: fec_contrato_tab_typ; luego creamos una variable de cada tipo: t_nombre y t_fec_contrato; en la sección ejecutable notamos como se asigna valores a dichas variables usando sus indices, lo cual se puede puede hacer manualmente o con una sentencia SELECT; también usamos un FOR LOOP para así recorrer nuestras tablas y mostrar los valores de los indices no nulos. Nota: el método/función EXISTS es explicado mas adelante.*/
---OUTPUT:
Métodos INDEX BY table.
Un método INDEX BY table es una función incorporada(built-in function) que opera sobre un Associative Array y es invocada usando la notación de punto.
Sintaxis:
table_name.method_name[ (parameters) ]
Ejemplos:
TYPE type_name IS TABLE OF
{ column_type [NOT NULL] | variable%TYPE [NOT NULL]
| table.column%TYPE [NOT NULL]
| table%ROWTYPE }
INDEX BY { PLS_INTEGER | BINARY_INTEGER
| VARCHAR2(<size>) } ;
identifier type_name;
Ejemplo:
SET SERVEROUTPUT ON
DECLARE
TYPE nombre_tab_typ
IS TABLE OF employees.last_name%TYPE
INDEX BY PLS_INTEGER;
TYPE fec_contrato_tab_typ
IS TABLE OF DATE
INDEX BY PLS_INTEGER;
t_nombre nombre_tab_typ;
t_fec_contrato fec_contrato_tab_typ;
BEGIN
t_nombre(1) := 'Pepe';
t_fec_contrato(1) := SYSDATE;
--
SELECT last_name,
hire_date
INTO t_nombre(6),
t_fec_contrato(6)
FROM employees
WHERE employee_id = 111;
--
FOR i IN t_nombre.FIRST..t_nombre.LAST LOOP
IF t_nombre.EXISTS(i) THEN
DBMS_OUTPUT.PUT_LINE(i||'. Nombre: '||t_nombre(i)||', Fecha: '||t_fec_contrato(i));
ELSE
DBMS_OUTPUT.PUT_LINE('Indice: '||i||' no asignado');
END IF;
END LOOP;
END;
/*En este ejemplo creamos un tipo tabla de nombres: nombre_tab_typ y un tipo tabla de fechas: fec_contrato_tab_typ; luego creamos una variable de cada tipo: t_nombre y t_fec_contrato; en la sección ejecutable notamos como se asigna valores a dichas variables usando sus indices, lo cual se puede puede hacer manualmente o con una sentencia SELECT; también usamos un FOR LOOP para así recorrer nuestras tablas y mostrar los valores de los indices no nulos. Nota: el método/función EXISTS es explicado mas adelante.*/
---OUTPUT:
Métodos INDEX BY table.
Un método INDEX BY table es una función incorporada(built-in function) que opera sobre un Associative Array y es invocada usando la notación de punto.
Sintaxis:
table_name.method_name[ (parameters) ]
Método
|
Descripción
|
EXISTS(n)
|
Devuelve TRUE si el índice n en el Associative Array existe.
|
COUNT
|
Retorna el numero de elementos contenidos en el Associative Array .
|
FIRST
|
·
Retorna el primer (mas pequeño) numero de indice del Associative Array.
· Devuelve NULL si el
|
LAST
|
· Retorna el último (mas grande) numero de indice del Associative Array.
· Devuelve NULL si el
|
PRIOR(n)
|
Retorna el numero de indice que antecede al indice n en el Associative Array.
|
NEXT(n)
|
Retorna el numero de indice que sigue(sucede) al indice n en el Associative Array.
|
DELETE
|
· DELETE remueve todos los elemento del Associative Array.
· DELETE(n) remueve el indice n en el Associative Array.
· DELETE(m, n) remueve todos los elementos en el rango m, n del Associative Array.
|
SET SERVEROUTPUT ON
DECLARE
TYPE dept_tab_typ
IS TABLE OF departments%ROWTYPE
INDEX BY PLS_INTEGER;
--
tabla_dept dept_tab_typ; -- Cada elemento en tabla_dept es un Record.
BEGIN
SELECT * INTO tabla_dept(1)
FROM departments
WHERE department_id = 10;
--
DBMS_OUTPUT.PUT_LINE('Código: '||tabla_dept(1).department_id ||
', Departamento de '||tabla_dept(1).department_name ||
', Código supervisor: '||tabla_dept(1).manager_id);
END;
/*En el ejemplo creamos un tipo table de Records: dept_tab_typ y creamos una variable(tabla_dept) de dicho tipo; luego asignamos el registro completo del departamento 10 de la tabla departments al indice 1 de nuestra variable; Posteriormente mostramos algunos de sus campos.*/
---OUTPUT:
SET SERVEROUTPUT ON
DECLARE
TYPE dept_tab_typ
IS TABLE OF departments%ROWTYPE
INDEX BY PLS_INTEGER;
--
tabla_dept dept_tab_typ; -- Cada elemento en tabla_dept es un Record.
v_cod_dept NUMBER(3);
BEGIN
FOR i IN 1..10 LOOP
v_cod_dept := i*10;
--
SELECT * INTO tabla_dept(i)
FROM departments
WHERE department_id = v_cod_dept;
END LOOP;
--
FOR i IN tabla_dept.FIRST..tabla_dept.LAST LOOP
DBMS_OUTPUT.PUT_LINE('Código: '||tabla_dept(i).department_id ||
', Departamento de '||tabla_dept(i).department_name ||
', Código supervisor: '||tabla_dept(i).manager_id);
END LOOP;
--
DBMS_OUTPUT.PUT_LINE('Cantidad Total: '||tabla_dept.COUNT);
END;
/*Aquí modificamos el ejemplo pasado; le agregamos dos FOR LOOP para así almacenar mas registros en nuestro associative array; Notar el uso de los métodos FIRST, LAST y COUNT..*/
---OUTPUT:
____________________________________________________________________________________
Los NESTED Table.
Nota: Para poder asignar valor a una variable tipo NESTED Table debe hacerlo invocando el nombre del tipo.
DECLARE
TYPE dept_tab_typ
IS TABLE OF departments%ROWTYPE
INDEX BY PLS_INTEGER;
--
tabla_dept dept_tab_typ; -- Cada elemento en tabla_dept es un Record.
BEGIN
SELECT * INTO tabla_dept(1)
FROM departments
WHERE department_id = 10;
--
DBMS_OUTPUT.PUT_LINE('Código: '||tabla_dept(1).department_id ||
', Departamento de '||tabla_dept(1).department_name ||
', Código supervisor: '||tabla_dept(1).manager_id);
END;
/*En el ejemplo creamos un tipo table de Records: dept_tab_typ y creamos una variable(tabla_dept) de dicho tipo; luego asignamos el registro completo del departamento 10 de la tabla departments al indice 1 de nuestra variable; Posteriormente mostramos algunos de sus campos.*/
---OUTPUT:
DECLARE
TYPE dept_tab_typ
IS TABLE OF departments%ROWTYPE
INDEX BY PLS_INTEGER;
--
tabla_dept dept_tab_typ; -- Cada elemento en tabla_dept es un Record.
v_cod_dept NUMBER(3);
BEGIN
FOR i IN 1..10 LOOP
v_cod_dept := i*10;
--
SELECT * INTO tabla_dept(i)
FROM departments
WHERE department_id = v_cod_dept;
END LOOP;
--
FOR i IN tabla_dept.FIRST..tabla_dept.LAST LOOP
DBMS_OUTPUT.PUT_LINE('Código: '||tabla_dept(i).department_id ||
', Departamento de '||tabla_dept(i).department_name ||
', Código supervisor: '||tabla_dept(i).manager_id);
END LOOP;
--
DBMS_OUTPUT.PUT_LINE('Cantidad Total: '||tabla_dept.COUNT);
END;
/*Aquí modificamos el ejemplo pasado; le agregamos dos FOR LOOP para así almacenar mas registros en nuestro associative array; Notar el uso de los métodos FIRST, LAST y COUNT..*/
---OUTPUT:
____________________________________________________________________________________
Los NESTED Table.
La funcionalidad de los NESTED Table (Tabla Anidada) es similar a la de los Associative Arrays; sin embargo, hay diferencias en su aplicación.
• Los NESTED Table son un tipo de dato válido a nivel de esquema, pero los Associative Arrays no. Por lo tanto, a diferencia de los Associative Arrays, los NESTED Table se pueden almacenar en la Base de Batos.
• El tamaño de un NESTED Table aumentar de forma dinámica, aunque el tamaño máximo es de 2 GB.
• La "Llave primaria" no puede ser un valor negativo (contrario a los Associative Arrays). Aunque se hace referencia a la primera columna como Llave primaria, no hay tal cosa en un NESTED Table. Mas bien es una columna con números.
• Los elementos pueden ser borrados desde cualquier parte, dejando espacios libres con una Llave primaria no secuencial. Las filas de un NESTED Table no están en ningún orden en particular.
• Al recuperar los valores de una tabla anidada, a las filas se le da subíndices consecutivos a partir de 1.
Nota: Para poder asignar valor a una variable tipo NESTED Table debe hacerlo invocando el nombre del tipo.
Sintaxis:
TYPE type_name IS TABLE OF
{column_type | variable%TYPE
| table.column%TYPE} [NOT NULL]
| table.%ROWTYPE
Ejemplo:
SET SERVEROUTPUT ON
DECLARE
TYPE typ_lugar
IS TABLE OF locations.city%TYPE;
--
v_oficinas typ_lugar;
BEGIN
v_oficinas := typ_lugar
(
'San Juan',
'Tokyo',
'Singapore',
'Oakland',
'Quito'
);
FOR i IN 1.. v_oficinas.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(v_oficinas(i));
END LOOP;
END;
/**/
---OUTPUT:
____________________________________________________________________________________
Los VARRAY.
SET SERVEROUTPUT ON
DECLARE
TYPE typ_lugar
IS TABLE OF locations.city%TYPE;
--
v_oficinas typ_lugar;
BEGIN
v_oficinas := typ_lugar
(
'San Juan',
'Tokyo',
'Singapore',
'Oakland',
'Quito'
);
FOR i IN 1.. v_oficinas.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(v_oficinas(i));
END LOOP;
END;
/**/
---OUTPUT:
____________________________________________________________________________________
Los VARRAY.
Una matriz de tamaño variable (VARRAY) es similar a un Associative Array, excepto que un VARRAY es limitado en tamaño.
• Un VARRAY es una tabla válida a nivel de esquema.
• Los elementos de tipo VARRAY se llaman VARRAYs.
• Los VARRAYs tienen un límite superior fijo. Se tiene que especificar el límite superior cuando se declaran. Esto es similar a las matrices en lenguaje C. El tamaño máximo de un VARRAY es de 2 GB, como en las tablas anidadas(NESTED Table).
• La distinción entre un NESTED Table y un VARRAY es el modo de almacenamiento físico. Los elementos de un VARRAY se almacenan en línea con los datos de la tabla a menos que el tamaño de la VARRAY sea mayor que 4 KB. Esto contrasta con los NESTED Table, que siempre se almacenan fuera de línea.
• Se puede crear un tipo VARRAY en la Base de Datos utilizando SQL.
Ejemplo:
SET SERVEROUTPUT ON
DECLARE
TYPE varray_typ
IS VARRAY(65) OF VARCHAR2(35);
---
varray_nombre varray_typ;
v_nombre VARCHAR2(35);
---
v_cont NUMBER := 0;
BEGIN
varray_nombre := varray_typ();
FOR i IN 111..120 LOOP
---
SELECT first_name||' '||last_name INTO v_nombre
FROM employees
WHERE employee_id = i;
---
v_cont := v_cont+1;
varray_nombre.EXTEND;
varray_nombre(v_cont) := v_nombre;
---
DBMS_OUTPUT.PUT_LINE('Nombre: '||varray_nombre(v_cont));
END LOOP;
END;
/*Aquí mostramos el uso de los tipos VARRAYs; Notar que es necesario invocar el constructor(equivalente al nombre del tipo base) para así poder asignar valores a una variable tipo VARRAY y también es necesario invocar el método EXTEND cada vez que se desee agregar un nuevo valor.*/
---OUTPUT:
DECLARE
TYPE varray_typ
IS VARRAY(65) OF VARCHAR2(35);
---
varray_nombre varray_typ;
v_nombre VARCHAR2(35);
---
v_cont NUMBER := 0;
BEGIN
varray_nombre := varray_typ();
FOR i IN 111..120 LOOP
---
SELECT first_name||' '||last_name INTO v_nombre
FROM employees
WHERE employee_id = i;
---
v_cont := v_cont+1;
varray_nombre.EXTEND;
varray_nombre(v_cont) := v_nombre;
---
DBMS_OUTPUT.PUT_LINE('Nombre: '||varray_nombre(v_cont));
END LOOP;
END;
/*Aquí mostramos el uso de los tipos VARRAYs; Notar que es necesario invocar el constructor(equivalente al nombre del tipo base) para así poder asignar valores a una variable tipo VARRAY y también es necesario invocar el método EXTEND cada vez que se desee agregar un nuevo valor.*/
---OUTPUT:
____________________________________________________________________________________
Resumen de los Tipos Colecciones.
Resumen de los Tipos Colecciones.
Las Matrices Asociativas(Associative Arrays).
Son conjuntos de pares clave-valor, donde cada clave es única y se utiliza para localizar un valor correspondiente en la matriz. La clave puede ser Numérica o Tipo Carácter. El valor de la matriz puede ser de tipo de dato escalar (valor individual) o de tipo de dato de Record (múltiples valores).
Debido a que las matrices asociativas están destinados para almacenar datos temporales, no se puede utilizar con sentencias SQL como INSERT.
Las Tablas Anidadas(NESTED Table).
Una tabla anidada tiene un conjunto de valores. En otras palabras, es una tabla dentro de una tabla. Las tablas anidadas son ilimitadas; es decir, el tamaño de la tabla puede aumentar de forma dinámica. Las tablas anidadas están disponibles tanto en PL/SQL como en la Base de Datos. Dentro de PL/SQL, las tablas anidadas son como matrices unidimensionales, cuyo tamaño puede aumentar de forma dinámica.
Las Matrices de Tamaño Variable(Varrays).
Son colecciones de elementos homogéneos que tienen un número fijo de elementos (aunque se puede cambiar el número de elementos en tiempo de ejecución). Ellos usan números secuenciales como subíndices. Es posible crear estos tipos en SQL, por lo cual se pueden almacenar en tabla de la Base de Datos.
_____________________________________________________________________________________