domingo, 18 de mayo de 2014

DBOR , colección de datos en SQL , VARRAY en Oracle

Oracle permite almacenar colecciones de datos del mismo tipo, de esta manera es posible almacenar en un vector (varray) o en forma de tabla anidada.

El tipo VARRAY  es un conjunto ordenado de elementos del mismo tipo, cada elemento tiene asociado un index. Los varray pueden tener longitud variable aunque es necesario establecer una longitud inicial.

1. Creamos el tipo de array :
create or replace type agenda_t as varray(3) of varchar2(20);

2. Un objeto que utilice el array "agenda_t" :
create or replace type homero as object(id_h number(2), mi_agenda agenda_t );

3. Una tabla para almacenar los objetos "homero":
create table homero_tab of homero ;

4. Insertamos un "homero" en la tabla "homero_tab":
insert into homero_tab values(1, agenda_t('3','2','1'));


5. Visualizar los datos almacenados:
select * from homero_tab;

otra forma de obtener los datos:
select value(m) from homero_tab m;

IMPORTANTE:  con el lenguaje SQL solo se pueden recuperar las listas (arrays) como un bloque, no se puede acceder a los datos de forma individual, para eso es necesario utilizar  PL/SQL 

Ejemplo de como recorrer la lista anterior : 
1.  set serveroutput start;  /*para poder imprimir por consola*/

2. 
declare
     lista homero;
     indice PLS_INTEGER;
begin
          select value(v)into lista from homero_tab v;
          indice := lista.mi_agenda.first;
          while(indice is not null) loop
                DBMS_OUTPUT.PUT_LINE('valor :' || lista.mi_agenda(indice)|| ' en indice :'||indice);
               indice := lista.mi_agenda.next(indice);
          end loop;
end;











DBOR, referencia entre objetos SQL

Cada objeto en una tabla tiene un identificador (id) , nosotros podemos definir atributos en una clase que sean una referencia a un objeto de otra tabla, de esta forma se puede implementar las relaciones entre tablas que almacenan objetos.

Oracle utiliza el operador "REF" , que devuelve el id de los objetos de una tabla de objetos. Un atributo de tipo "REF" guarda la referencia a un objeto del tipo definido e implementa una relacion entre los dos tipos de objetos. Esta referencia permite acceder a los objetos referenciados y modificar la información , pero no se puede operar directamente sobre la referencia. (dicho con otras palabras, no es un puntero) .


Explicacion para tontos:
Tienes una tabla A que guarda objetos A, y una tabla B que guarda objetos B,  en la clase A tienes un atributo que hace referencia a un objeto B , pero no necesariamente tiene que existir dentro de la tabla B.

entonces , si quieres que en la tabla A solo se guarden objetos con referencia a objetos B , QUE SÍ EXISTEN,  y se guardan en la tabla B, tienes que especificarlo con el operador "SCOPE" ,  de esta forma se evita guardar espacio en memoria para un ipotetico objeto B que aun no existe en la tabla B.


El siguiente ejemplo muestra como se restringe que dentro de la tabla B solo se puedan añadir objetos que  sí existen dentro de la tabla A

Ejemplo :
CREATE TYPE  obj_A  AS OBJECT( .... .... .... ); /* Clase  A*/

CREATE TABLE    tab_A    OF    obj_A;

CREATE TYPE   obj_B   AS OBJECT (     /* Clase  B*/
             ordnum NUMBER,
             cliente    REF   obj_A,
             fechpedido DATE,
             direcentrega direccion_t);

CREATE TABLE    tab_B    OF obj_B  (
             PRIMARY KEY (ordnum),
             SCOPE FOR (cliente) IS tab_A);
);



PROBLEMA :  al borrar un objeto de la tabla  A , en la tabla B los objetos aun mantienen la referencia al objeto borrado, y al hacer un select , Oracle muestra un error de referencia colgada (dangling references)
, para evitar esto se pude deshacer la referencia con "DEREF", pero  la solución más facil es hacer esa referencia que sea una clave externa (foreign key) . La tabla B quedaría de esta forma:
CREATE TABLE    tab_B    OF obj_B  (
             PRIMARY KEY (ordnum),
             FOREIGN KEY  (cliente) REFERENCES  tab_A,
            ON DELETE CASCADE    /*si se borrar un objeto A se borran todos los B que estén relacionados */
);





























DBOR ordenar y comparar objetos en SQL

Para poder ordenar o comparar objetos en Sql se utilizan las claves "MAP" y "ORDER".

Oracle es incapaz de deducir si un objeto es mayor que otro, por lo tanto , es necesario implementar una de estas funciones (solo se puede implementar una o la otra, no ambas a la vez)

MAP, nos sirve para comparar objetos y es llamado automaticamente cuando en un  SELECT  se utiliza DISTINCT, ORDER BY  y GROUP BY.

Ejemplo, creamos un objeto "melonT":

CREATE OR REPLACE TYPE melonT AS  OBJECT
(
id_melon number(2);
nombre  varchar2(20);
MAP MEMBER FUNCTION id_melon  RETURN NUMBER;  /*cabecera del metodo 'id_melon  ' */
);

/* creamos el metodo 'id_melon  ' */

CREATE OR REPLACE TYPE BODY melonT   AS
      MAP MEMBER FUNCTION id_melon  RETURN NUMBER
      BEGIN
            RETURN id_melon;   /*return: un atributo que sea clave primaria */
      END;
END;
----------------------------------------------------

ORDER , a diferencia de MAP  , solo puede comparar la diferencia entre  2 objetos y la sintaxis es más estricta. El resultado de "ORDER"  tiene que ser un valor que se pueda comparar (un tipo primitivo), el retorno de la función es la resta del valor del propio objeto menos el valor del objeto pasado por parametro, es decir, si la salida es cero los dos objetos son son iguales, si la salida es negativa el objeto que es comparado es más pequeño y si la salida es positiva el objeto a comparar es mayor el objeto con el que se compara.


Ejemplo :

CREATE OR REPLACE TYPE melonT AS  OBJECT
(
id_melon number(2);
nombre  varchar2(20);
ORDER MEMBER FUNCTION equals(otroObj   IN  melonT ) RETURN INTEGER;  /*cabecera del metodo 'equals' */
);

CREATE OR REPLACE TYPE BODY melonT   AS
      MAP MEMBER FUNCTION equals(otroObj   IN  melonT )  RETURN INTEGER
      BEGIN
            RETURN  id_melon -  ortroObj.id_melon;
      END;
END;










DBOR Bases de Datos Objecte-Relacionals



Instrucciones basicas en SQL para la creación de objetos y tablas de objetos:

Comentario de texto en SQL se hace con 2 guiones "--" al pricipio de la linea!

1. crear un objeto
-- Para heredar de un objeto creado, se le tiene que especificar "NOT FINAL" .

CREATE OR REPLACE TYPE nom_objeto AS OBJECT (
           atributo1  VARCHAR2(123)  [, atributo2  NUMBER(2) ] [ ,atributo3 DATE] ,
           MEMBER FUNCTION getAtributo1 return VARCHAR2,
           MEMBER PROCEDURE setAtributo1(nuevoValor  VARCHAR2),
           
)  NOT FINAL  ;

Ejemplo, heredar del objeto "nom_objeto":

CREATE OR REPLACE TYPE nom_objeto2  UNDER  nom_objeto  (
--atributos
--declaración de metodos
);


2. definir los metodos de cada objeto creado :

CREATE OR REPLACE TYPE BODY  nom_objeto AS 

     MEMBER FUNCTION getAtributo1 RETURN VARCHAR AS 
          --entre "as" y "begin" inicializar variables de esta funcion, si hace falta.
          BEGIN
               RETURN SELF.atributo1;
          END getAtributo;


     MEMBER PROCEDURE setAtributo1(nuevoValor   VARCHAR2)  AS 
          BEGIN
               SELF.atributo1 : =  nuevoValor ;
          END setAtributo;
END;


3. Crear tabla de este objeto :


CREATE TABLE nomTabla OF nom_objeto( PRIMARY KEY(atributo1));

INSERT INTO nomTabla VALUES('valor del atributo1 del objeto' );
INSERT INTO nomTabla VALUES('hola ' );
INSERT INTO nomTabla VALUES('mundooo ' );



SELECT * FROM nomTabla  T  WHERE  T.atributo1 = '   hola  '  ;

result :

ATRIBUTO1
---------------------------------------------------
hola                                                              

La función VALUE  sirve para obtener la misma estructura del tipo de objeto de una tabla. En un select normal se obtiene los valores de los atributos, mietras que utilizando la funcion value() se obtiene el objeto entero .

SELCET  VALUE(P) FROM  nomTabla P ;

result:

VALUE(P)
---------------------------------------------------
SYSTEM.ATRIBUTO1(' valor del atributo del objeto ')     
SYSTEM.ATRIBUTO1(' hola')     
SYSTEM.ATRIBUTO1(' mundo  ')