Objetivos
- Conocer los Tipos de Objetos de Oracle (Object Types).
- El Concepto.
- Su Estructura.
- Sus Componentes.
- Describir sus usos.
Concepto
- Programación Orientada a Objetos: es un método de programación basado en una jerarquía de clases y objetos bien definidos que cooperan entre sí con el fin de llevar a cabo una tarea.
- Métodos y Atributos:
- Los Atributos son similares a las variables, los mismos deben tener un nombre y un tipo de dato. El nombre debe ser único dentro del objeto (pero puede ser reutilizado en otros tipos de objetos).
- Un Método es un subprograma declarado en la especificación del objeto utilizando la palabra clave MEMBER o STATIC. Los métodos no pueden tener el mismo nombre que el objeto o el de cualquiera de sus atributos.
- Sus Usos:
Los tipos de objetos permiten dividir grandes sistemas en entidades lógicas. Esto le permite crear componentes de software que sean modulares, mantenibles y reutilizables entre proyectos y equipos.
Al asociar el código con los datos, los tipos de objeto mueven el código de mantenimiento de secuencias de comandos SQL y bloques PL/SQL en métodos. En lugar de escribir un procedimiento largo que hace cosas diferentes basadas en algún valor de parámetro, puede definir diferentes tipos de objetos y hacer que cada operación sea ligeramente diferente. Al declarar un objeto del tipo correcto, asegúrese de que sólo puede realizar las operaciones para ese tipo.
Los tipos de objetos permiten un modelado de datos realista. Las entidades y relaciones complejas del mundo real se correlacionan directamente en tipos de objetos. Los tipos de objetos se asignan directamente a las clases definidas en lenguajes orientados a objetos como Java y C++.
Los Objetos de Oracle
Un tipo de objeto es un tipo de dato compuesto definido por el usuario que encapsula una estructura de datos junto con las funciones y procedimientos necesarios para manipular los datos. Las variables que forman la estructura de datos se llaman atributos. Las funciones y procedimientos que caracterizan el comportamiento del tipo de objeto se conocen como métodos. Un tipo especial de método llamado constructor crea una nueva instancia del tipo de objeto y rellena sus atributos.
Los tipos de objetos deben crearse a través de SQL y almacenarse en una Base de Datos Oracle, donde pueden ser compartidos por muchos programas. Cuando se define un tipo de objeto mediante la sentencia CREATE TYPE, se crea una plantilla abstracta para algún objeto del mundo real. La plantilla especifica los atributos y comportamientos que el objeto necesita en el entorno de la aplicación.
Cabe destacar que la estructura de datos formada por el conjunto de atributos es pública, y por lo tanto visible para los programas clientes. Sin embargo, en programas bien diseñados, estos atributos no son manipulados directamente. En su lugar, se utiliza el conjunto de métodos proporcionados, de modo que los datos se mantienen en un estado adecuado.
Su estructura
Al igual que un paquete, un tipo de objeto tiene una especificación y un cuerpo. La especificación define la interfaz del objeto; Declara un conjunto de atributos junto con las operaciones (métodos) para manipular los datos. El cuerpo define el código para los métodos.
Toda la información que un programa necesita para usar los métodos está en la especificación. Puede cambiar el cuerpo sin cambiar la especificación, y sin afectar a los programas del cliente.
En la especificación, todos los atributos deben declararse antes que cualquier método. Si una especificación declara únicamente atributos, el cuerpo del objeto es innecesario. No se pueden declarar atributos en el cuerpo. Tenga en cuenta que todas las declaraciones en la especificación del objeto son públicas (visibles fuera del objeto).
Sus componentes
Un objeto encapsula datos y operaciones. Puede declarar atributos y métodos en la especificación de un objeto, no en constantes, excepciones, cursores o en tipos. Debe declarar al menos un atributo (el máximo es 1000). Los métodos son opcionales.
Los Atributos: Al igual que una variable, se declara un atributo con un nombre y un tipo de dato. El nombre debe ser único dentro del tipo de objeto (pero puede ser reutilizado en otros tipos de objetos). El tipo de dato puede ser cualquier tipo de Oracle excepto:
- LONG y LONG RAW.
- ROWID y UROWID.
- Tipos específicos de PL/SQL como: BINARY_INTEGER (y sus subtipos), BOOLEAN, PLS_INTEGER, RECORD, REF CURSOR, %TYPE, y %ROWTYPE.
- Tipos definidos en Paquetes de PL/SQL.
No puede inicializar un atributo en su declaración utilizando el operador de asignación o la cláusula DEFAULT. Además, no puede imponer la restricción NOT NULL en un atributo. Sin embargo, los objetos pueden almacenarse en tablas de Base de Datos en las que puede imponer restricciones.
La estructura de datos puede ser muy compleja. Por ejemplo, el tipo de dato de un atributo puede ser otro tipo de objeto (conocido como tipo de objeto anidado). Eso le permite crear un tipo de objeto complejo a partir de tipos de objetos más simples. Algunos tipos de objetos como colas, listas y árboles son dinámicos, lo que significa que pueden crecer a medida que se utilizan. Los tipos de objetos recursivos, que contienen referencias directas o indirectas a sí mismos, permiten modelos de datos altamente sofisticados.
Métodos: En general, un método es un subprograma declarado en una especificación de tipo de objeto utilizando la palabra clave MEMBER o STATIC. El método no puede tener el mismo nombre que el tipo de objeto o que cualquiera de sus atributos. Los métodos MEMBER se invocan en instancias y los métodos STATIC se invocan en el tipo de objeto, no en sus instancias.
Al igual que los subprogramas contenidos en paquetes, los métodos tienen dos partes: una especificación y un cuerpo. La especificación consiste del nombre, una lista de parámetros (opcional) y, para las funciones, un tipo de retorno. El cuerpo es el código que se ejecuta para llevar a cabo una tarea específica.
Para cada especificación de un método contenido en una especificación de objeto, debe haber un cuerpo de método contenido en el cuerpo del objeto o el método como tal debe ser declarado NOT INSTANTIABLE, esto último para indicar que el cuerpo sólo está presente en subtipos de este tipo. Para hacer coincidir las especificaciones del método y los cuerpos, el compilador PL/SQL hace una comparación token-by-token de sus encabezados; Por lo cual los encabezados deben coincidir exactamente.
La Sentencia CREATE TYPE
Utilizamos la sentencia CREATE TYPE para crear la especificación de un tipo de objeto(Object Type), un tipo de objeto SQLJ(SQLJ Object Type), una matriz de nombres variables(Varray), un tipo de tabla anidada(Nested Table Type) o un tipo de objeto incompleto(Incomplete Object Type). En esta pulicacion nos enfocaremos en los tipos de objeto ya que es el tema en cuestion.
Para crear un tipo de objeto usamos las sentencias CREATE TYPE y CREATE TYPE BODY. La sentencia CREATE TYPE especifica el nombre del objeto, sus atributos, métodos y otras propiedades. La sentencia CREATE TYPE BODY contiene el desarrollo de los métodos que implementan el tipo.
Sintaxis Especificación
CREATE [ OR REPLACE ]
TYPE [ schema. ]type_name
[ OID 'object_identifier' ]
[ invoker_rights_clause ]
{ { IS | AS } OBJECT
| UNDER [schema.]supertype
}
[ sqlj_object_type ]
[ ( attribute datatype
[ sqlj_object_type_attr ]
[, attribute datatype
[ sqlj_object_type_attr ]...
[, element_spec
[, element_spec ]...
]
)
]
[ [ NOT ] FINAL ]
[ [ NOT ] INSTANTIABLE ] ;
Sintaxis Cuerpo
CREATE [ OR REPLACE ] TYPE BODY [ schema. ]type_name
{ IS | AS }
{ subprogram_declaration
| map_order_func_declaration
}
[, { subprogram_declaration
| map_order_func_declaration
}
]...
END;
Nota: el tema de los Tipos de Objetos de Oracle es bastante profundo de modo que si tratamos de abarcar todos los conceptos tendríamos que incluir muchos detalles que son vitales por lo cual la publicación seria extensa. Es por esta razón, en esta publicación vamos a tocar los puntos básicos y esenciales del tema en cuestión, esto con el fin de facilitar el entendimiento de los temas, con la intención de expandirlo en futuras publicaciones.
Ejemplos
A continuación creamos el tipo typ_bank_account para representar una cuenta bancaria.
CREATE OR REPLACE TYPE hr.typ_bank_account IS OBJECT
(account_num NUMBER,
account_holder VARCHAR2(40),
balance NUMBER,
interest_rate NUMBER);
El siguiente bloque anónimo muestra como utilizar el tipo de dato typ_bank_account. Notar que para asignar nuevos valores a un variable de ese tipo, es necesario invocar su constructor(nombre del tipo objeto) pasandole valores a cada uno de sus atributos, mientras que para extraer los valores almacenados, se utiliza el nombre de la variable seguido de un punto ‘.’ mas el nombre del atributo en cuestión
SET SERVEROUTPUT ON
DECLARE
v_account hr.typ_bank_account;
BEGIN
v_account := hr.typ_bank_account
(1000245,
'Julio Tiburcio Vargas',
60000,
0.015);
DBMS_OUTPUT.PUT_LINE
('Banco La Minita, donde su dinero pesa!!!'||CHR(10)||
RPAD('-',40,'-')||CHR(10)||
'Detalles de Cuenta:'||CHR(10)||
'Cliente: '||v_account.account_holder||CHR(10)||
'Cuenta#: '||v_account.account_num||CHR(10)||
'Balance Disponible: '||v_account.balance||CHR(10)||
'Tasa de Interés: '||v_account.interest_rate*100||'% Anual');
END;

A continuación creamos el tipo de dato typ_account_holder el cual posteriormente utilizaremos para modificar el typ_bank_account previamente visto, de esta manera agregamos complejidad al ejemplo.
CREATE OR REPLACE TYPE hr.typ_account_holder IS OBJECT
(identity_id NUMBER,
first_name VARCHAR2(20),
last_name VARCHAR2(20),
sex CHAR(1),
birth_date DATE,
address VARCHAR2(100),
contact_number VARCHAR2(10),
email VARCHAR2(60));
Ahora modificamos el tipo de dato typ_bank_account para que el atributo account_holder sea del tipo de dato typ_account_holder.
CREATE OR REPLACE TYPE hr.typ_bank_account IS OBJECT
(account_num NUMBER,
account_holder hr.typ_account_holder,
balance NUMBER,
interest_rate NUMBER);
El siguiente bloque anonimo muestra el uso del tipo de datos typ_bank_account ahora con el modficado atributo account_holder de tipo dato typ_account_holder. Notar que se crearon dos variables tipo objeto typ_account_holder y typ_bank_account respectivamente.
SET SERVEROUTPUT ON
DECLARE
v_holder hr.typ_account_holder;
v_account hr.typ_bank_account;
BEGIN
v_holder := hr.typ_account_holder
('01201087659',
'Julio',
'Tiburcio Vargas',
'M',
TO_DATE('25/02/1984','DD/MM/YYYY'),
'Calle la Palma #3, El Higuero, San Cristóbal, RD.',
'8090002277',
'jtibur_v@plsqlmagico.com');
v_account := hr.typ_bank_account
(1000245,
v_holder,
60000,
0.015);
DBMS_OUTPUT.PUT_LINE
('Banco La Minita, donde su dinero pesa!!!'||CHR(10)||
RPAD('=',40,'=')||CHR(10)||
'Datos del Titular:'||CHR(10)||
'Nombre: '||v_account.account_holder.first_name||' '
||v_account.account_holder.last_name||CHR(10)||
'Sexo: '||v_account.account_holder.sex||CHR(10)||
'Edad: '||
TRUNC(
MONTHS_BETWEEN(
SYSDATE, v_account.account_holder.birth_date)/12
)||CHR(10));
DBMS_OUTPUT.PUT_LINE
(RPAD('-',40,'-')||CHR(10)||
'Detalles de Cuenta:'||CHR(10)||
'Cuenta#: '||v_account.account_num||CHR(10)||
'Balance Disponible: '||v_account.balance||CHR(10)||
'Tasa de Interés: '||v_account.interest_rate*100||'% Anual');
END;

Ahora creamos el tipo de datos typ_account_details.
CREATE OR REPLACE TYPE hr.typ_account_details IS OBJECT
(account_number NUMBER,
account_title VARCHAR2(30),
account_type CHAR(1),
open_date DATE,
balance NUMBER,
last_tranc CHAR(1),
last_tranc_date DATE,
interest_rate NUMBER);
Ahora creamos el tipo de datos t_account_details el cual representa un tipo de datos tabla basado en typ_account_details, por lo que un registro de t_account_details podria hacer referencia uno o varios registros del tipo de datos typ_account_details.
CREATE OR REPLACE TYPE hr.t_account_details
IS TABLE OF hr.typ_account_details;
Una vez más modificamos el tipo de datos typ_bank_account para el atributo account sea del tipo de datos t_account_details. Ahora el tipo de datos typ_bank_account permite tener un account_holder o cliente con multiples cuentas diferentes.
CREATE OR REPLACE TYPE hr.typ_bank_account IS OBJECT
(account_holder hr.typ_account_holder,
account hr.t_account_details);
El siguiente ejemplo muestro el uso del tipo de datos typ_bank_account con las últimas modificaciones realizadas al campo account ahora del tipo de datos t_account_details. Para poder asignar valores a una variable de tipo objeto tabla es necesario invocar su constructor sin parámetros (esto porque no tiene atributos), luego es necesario invocar su método EXTEND que agrega un registro en la tabla, posteriormente para asignar los valores a cada atributo del registro, es necesario invocar su constructor como tal. Notar que es necesario indicar el registro de la variable tipo tabla al cual se desea agregar los datos: variable(índice) :=. El medio de extracción es igual: variable(índice).nombre_atributo.
SET SERVEROUTPUT ON
DECLARE
v_account hr.typ_bank_account;
v_holder hr.typ_account_holder;
v_acc_detail hr.t_account_details;
v_acc_type CHAR(1);
v_open_date DATE;
v_int_rate NUMBER(3,3);
BEGIN
v_holder := hr.typ_account_holder
('01201087659',
'Julio',
'Tiburcio Vargas',
'M',
TO_DATE('25/02/1984','DD/MM/YYYY'),
'Calle la Palma #3, El Higuero, San Cristóbal, RD.',
'8090002277',
'jtibur_v@plsqlmagico.com');
v_acc_detail := hr.t_account_details();
FOR i IN 1..3 LOOP
CASE
WHEN i<2 THEN
v_acc_type := 'D';
v_open_date := TO_DATE('01/04/2002','DD/MM/YYYY');
v_int_rate := .015;
WHEN i>2 THEN
v_acc_type := 'P';
v_open_date := TO_DATE('09/09/2012','DD/MM/YYYY');
v_int_rate := .16;
ELSE
v_acc_type := 'C';
v_open_date := TO_DATE('07/07/2005','DD/MM/YYYY');
v_int_rate := .06;
END CASE;
v_acc_detail.EXTEND;
v_acc_detail(i) := hr.typ_account_details(1000244+i,
'Cuenta '||i,
v_acc_type,
v_open_date,
TRUNC(DBMS_RANDOM.value(60000,150000),2),
'R',
SYSDATE - i,
v_int_rate);
END LOOP;
v_account := hr.typ_bank_account(v_holder,
v_acc_detail);
DBMS_OUTPUT.PUT_LINE('Cliente: '||v_account.account_holder.first_name||' '
||v_account.account_holder.last_name||CHR(10)||
RPAD('=',35,'=')||CHR(10)||
'Cuentas: '||CHR(10)||
RPAD('-',35,'-')||CHR(10));
FOR i IN v_account.account.FIRST..v_account.account.LAST LOOP
DBMS_OUTPUT.PUT_LINE('Número : '||v_account.account(i).account_number||CHR(10)||
'Tipo : '||v_account.account(i).account_type||CHR(10)||
'Fecha Apertura : '||v_account.account(i).open_date||CHR(10)||
'Balance : '||v_account.account(i).balance||CHR(10)||
'Tasa de Interés : '||v_account.account(i).interest_rate*100||'% Anual'||CHR(10)||
'...');
END LOOP;
END;

Sentencia DROP TYPE
Utilice la sentencia DROP TYPE para eliminar la especificación y el cuerpo de un Tipo de Objeto, un Varray o un Tipo de Tabla Anidada(Nested Table).
Sintaxis
DROP TYPE [ schema. ] type_name [ FORCE | VALIDATE ];
Tenga en cuenta que sólo puede hacer DROP de tipos sin dependencias de otros tipos o de tablas(solo aplica si no se especifica FORCE ).
- Cláusula FORCE: Especifique FORCE para eliminar el Tipo incluso si tiene Objetos de Base de Datos dependientes. Oracle marca UNUSED todas las columnas dependientes del tipo que se va a eliminar, y esas columnas se vuelven inaccesibles.
Nota: Oracle no recomienda usar FORCE, esta operación no es recuperable y podría hacer que los datos de las tablas o columnas dependientes se vuelvan inaccesibles.
- Cláusula VALIDATE: Si especifica VALIDATE al hacer DROP de un Tipo, Oracle Verifica las instancias almacenadas de este tipo en columnas sustituibles de cualquiera de sus supertipos(tipos padre). Si no se encuentran tales instancias, se completa la operación de eliminación.
Esta cláusula sólo es significativa para los subtipos(tipos hijo). Oracle recomienda el uso de esta opción para eliminar con seguridad subtipos que no tienen ningún tipo explícito o dependencias de tabla.
Ejemplos
DROP TYPE hr.typ_bank_account;
DROP TYPE hr.typ_account_holder;
DROP TYPE hr.t_account_details;
DROP TYPE hr.typ_account_details;
Conclusión
Los objetos en PL/SQL representan una poderosa extensión del lenguaje, ya que permiten modelar estructuras complejas de datos de manera más cercana al mundo real. Gracias a ellos, es posible encapsular atributos y métodos dentro de una misma entidad, promoviendo la reutilización de código y una mayor organización en las aplicaciones Oracle.
Su uso facilita la implementación de soluciones orientadas a objetos dentro de un entorno relacional, ofreciendo flexibilidad y robustez en el diseño de sistemas. En definitiva, dominar los tipos de objetos en PL/SQL no solo amplía las capacidades técnicas del desarrollador, sino que también abre la puerta a construir aplicaciones más escalables, claras y eficientes.

