SGBDOO. Objetos en Oracle
Presentación de la Universidad Rey Juan Carlos
Teoria de BR Objeto Relacionales
Definición de un objeto
Para definir un objeto se crea un nuevo tipo.
Se crea un constructor por
defecto que debe recibir los atributos en el orden en el que se hayan
definido al crear el nuevo tipo
A) Creamos un objeto
del tipo TABLON con 2 atributos (largo y ancho) y 3 métodos (area,
perimetro y precio al que se le pasará un precio por metro cuadrado):
create or replace TYPE TABLON AS OBJECT (
largo integer,
ancho integer,
member function area return integer,
member function perimetro return integer,
member function precio (p float) return float
);
B) Definimos el cuerpo del objeto (la definición de los métodos)
create or replace TYPE BODY TABLON AS
member function area return integer AS
resultado integer;
BEGIN
resultado:=largo*ancho;
RETURN resultado;
END area;
member function perimetro return integer AS
resultado integer;
BEGIN
resultado:=2*largo+2*ancho;
RETURN resultado;
END perimetro;
member function precio (p float) return float AS
resultado float;
BEGIN
resultado:=area*p;
RETURN resultado;
END precio;
END;
Uso de sentencias SQL con objetos:
Creación de tablas en las que uno de los campos es un objeto.
Crearemos una tabla llamada mueble que contiene objetos del tipo TABLON (ver dibujo) :
CREATE TABLE MUEBLE ( NUMERO INT, CANTIDAD INT, ELEMENTO CHEMA.TABLON);
Inserción de registros en la tabla MUEBLE
Creamos los registros del mueble:
insert into mueble values(1,2,new tablon(180,30));
insert into mueble values(2,3,new tablon(100,30));
insert into mueble values(3,1,new tablon(120,30));
Operaciones sobre el mueble:
Ver los componentes: select * from mueble m;
Dimensiones de las tablas: select m.cantidad,m.elemento.largo,m.elemento.ancho from mueble m;
Areas,
perímetros y coste de cada tabla (a 23 €/m2): select
m.cantidad,m.elemento.area(),m.elemento.perimetro(),m.elemento.precio(0.0023)
from mueble m;
Precio total del mueble (a 23 €/m2): select sum(m.cantidad*m.elemento.precio(0.0023)) from mueble m; ------> 53,82 €
- Se pueden hacer condiciones como m.elemento.area()<100;
- operaciones de actualización como update mueble m set m.elemento.largo=200 where numero=1; para hacer el mueble de 200 cm de alto en vez de 180
Uso de objetos en funciones
create or replace FUNCTION funcion_con_objeto(a int,b int) RETURN VARCHAR2 AS
r1 tablon;
BEGIN
r1 := NEW tablon(a,b);
return 'El area es '||r1.area();
END;
select funcion_con_objeto(10,20) from dual; devuelve el texto ‘El area es 200’
Atributos multivaluados
La
1FN indica que no deben asistir atributos multivaluados. Sin embargo,
en BDOO se puede crear atributos que puedan tener más de un valor y ser
manejados de una forma sencilla
Colecciones
Es un grupo de
elementos del mismo tipo. Por ejemplo, supongamos que se desea
almacenar datos atómicos de los empleados de una empresa (por ejemplo,
el nombre) junto con el nombre de sus hijos (multivaluado). En BD
relacionales se generan 2 tablas: empleados e hijos. La FK de hijos es
la PK de empleados. En BD OO se crearía una colección:
Tipos - Nuevo Tipo - Nombre=colec_hijos - Tipo=tipo de matriz - Definir - Compilar
CREATE OR REPLACE TYPE COLEC_HIJOS AS VARRAY(10) OF varchar2(30) ;
De
esta forma, se define el tipo colec_hijos que puede almacenar un máximo
de 10 hijos, cada uno con hasta 30 caracteres en su nombre
Una vez definida la colección, se puede crear la tabla empleado que contiene un campo del tipo colecc_hijos
CREATE TABLE "CHEMA"."EMPLEADO" (
"ID" NUMBER,
"NOMBRE" VARCHAR2(20 BYTE),
"APELLIDOS" VARCHAR2(20 BYTE),
"HIJOS" "CHEMA"."COLEC_HIJOS" ,
CONSTRAINT "PRK1" PRIMARY KEY ("ID")
)
A continuación se pueden insertar registros en la tabla empleado y seleccionarlos:
No es posible acceder a los elementos individuales de una colección desde un comando SQL. Es preciso realizar un programa PL-SQL
Tablas anidadas
Existe la posibilidad de no limitar la cantidad de valores dentro del atributo multivaluado, haciendo que el campo sea del tipo tabla
En el ejemplo anterior, el número máximo de hijos era de 10. Podemos hacerlo ilimitado definiendo un tipo tabla:
CREATE OR REPLACE TYPE TABLA_HIJOS AS TABLE OF varchar2(30);
Después
se crea la tabla empleado con un campo del tipo tabla_hijos. Es preciso
desde el editor de la tabla dar un nombre a la tabla anidada -nested table- (en nuestro caso t_hijos)
De
esta forma se pasa de tablas de 2 dimensiones (fila, columna) a 3
dimensiones (fila, columna, fila de tipos). Evidentemente se puede
tener varios niveles de tablas anidadas
Ver el gráfico con las distintas órdenes para insertar, seleccionar, borrar, sustituir, ...
Lo más útil es
- Crear un tipo objeto con sus atributos
- Crear un tipo tabla con el objeto anterior
- Crear una tabla con un campo que sea una tabla anidada del objeto creado en el punto 2
Ejemplo: queremos almacenar los siguientes datos de nuestros clientes:
- Identificativo del cliente
- Nombre
- Teléfono del cliente
Pero
nos damos cuenta que un cliente tiene teléfono personal de casa y
móvil, teléfono de la empresa y móvil de la empresa, es decir, de 1 a 4
telefónos
1) Creamos un objeto del tipo telefono con 2 campos: tipo (casa, trabajo, fijo, móvil, ...) y el numero
CREATE OR REPLACE TYPE TELEFONO AS OBJECT(tipo varchar2(30),numero number)
2) Creamos un tipo tabla llamado listin que puede contener múltiples objetos del tipo teléfono
CREATE OR REPLACE TYPE LISTIN AS TABLE OF telefono;
3) Creamos una tabla con los datos de un cliente entre los que se encuentra un campo del tipo listin
De esta forma, se crea una tabla en la que el campo TELFS es otra tabla con 2 campos: tipo y numero
ID | NOMBRE | APELLIDOS | TELS |
1 | Francisco | Perez | TIPO | NUMERO | Casa | 111 | Movil | 666 | Trabajo | 777 |
|
2 | Esperanza | Jimenez | |
Usamos las distintas órdenes SQL con la tabla ortriginal (cliente) y la tabla anidada (tel_tab):
-- Inserto un cliente con 2 telefonos
INSERT
INTO cliente (ID,nombre,apellidos,telfs) values
(1,'Francisco','Perez',listin(telefono('Casa',111),telefono('Movil',666)));
-- Inserto un cliente con 1 telefono
INSERT INTO cliente (ID,nombre,apellidos,telfs) values (2,'Esperanza','Jimenez',listin(telefono('Casa',222)));
-- Añado un telefono al cliente 1. Ver el uso de la palabra clave TABLE que recibe la tabla anidada
INSERT INTO TABLE (SELECT telfs FROM cliente WHERE id=1) VALUES ('Trabajo',777);
-- Listado de clientes y sus telefonos (desanidamiento)
SELECT t1.nombre,t1.apellidos,t2.tipo,t2.numero FROM cliente t1,TABLE(t1.telfs) t2;
-- Busqueda de un telefono concreto
SELECT t1.nombre,t1.apellidos,t2.tipo,t2.numero FROM cliente t1,TABLE(t1.telfs) t2 WHERE t2.numero=777;
-- Telefonos de Perez
SELECT t2.tipo,t2.numero FROM cliente t1,TABLE(t1.telfs) t2 WHERE t1.apellidos='Perez';
-- Cambio el telefono de casa de Perez
UPDATE TABLE (SELECT telfs FROM cliente WHERE apellidos='Perez') SET numero=112 WHERE tipo='Casa';
-- Borro el telefono Movil de Perez
DELETE FROM TABLE (SELECT telfs FROM cliente WHERE apellidos='Perez') WHERE tipo='Movil';
Acceso a Objetos Oracle desde Java
// Copiar la librería ojdbc6.jar (u ojdbc5.jar) en C:/BlueJ/lib/userlib.
// La librería está en el servidor de Oracle
import java.sql.*;
class Oracle{
public static void main (String args []) throws Exception {
DriverManager.registerDriver (new oracle.jdbc.driver.OracleDriver());
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection conn = DriverManager.getConnection
("jdbc:oracle:thin:@192.168.0.253:1521:asir2", "chema", "chema");
Statement stmt = conn.createStatement();
// Accedo a la tabla que tiene el campo nombre(varchar2) y recta(del tipo rectangulo)
ResultSet rset = stmt.executeQuery("select nombre,recta from rectangulos");
while (rset.next()){
// Obtengo el campo nombre
String nombre=rset.getString(1);
// Obtengo el objeto rectangulo
oracle.sql.STRUCT objeto = (oracle.sql.STRUCT) rset.getObject(2);
// Saco sus atributos
Object[] atributos = objeto.getAttributes();
java.math.BigDecimal alto = (java.math.BigDecimal) atributos[0];
java.math.BigDecimal ancho = (java.math.BigDecimal) atributos[1];
// ¿Y para acceder a la function -método- dime_area()?
// Esto no se hacerlo
// Imprimo la fila completa
System.out.println("Nombre: "+nombre+ ". Dimensiones: "+alto+" x
"+ancho);
}
// Para INSERT, DELETE o UPDATE, se usa executeUpdate
//stmt.executeUpdate("INSERT INTO rectangulos VALUES ('quinto',new
rectangulo(5,555))");
// Puedo hacer uso de los métodos en la sentencia SELECT que ataca a Oracle
rset = stmt.executeQuery("SELECT nombre,r.recta.dime_area() FROM
rectangulos r WHERE r.recta.dime_area()>100");
System.out.println("Rectangulos con area mayor de 100:");
while (rset.next()){
System.out.println(rset.getString(1)+" --> "+rset.getInt(2));
}
stmt.close();
}
}