style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-5164839828746352"
data-ad-slot="7563230308">

Rel Project: Una base de datos relacional (en Java) como deberian de ser? Parte II: Historia, Relvars, Cerradura....

Un poco de Historia y teoría

En la primera parte de esta serie de “blog posts” sobre el proyecto Rel, hable acerca que de Rel era una base de datos verdaderamente relacional, pero no aclare mucho acerca de que distingue a una base de datos verdaderamente relacional de una que no lo es. Bueno, revisitemos la definición de una base de datos relacional.

Nos interesan, en este caso, particularmente 2 de las 12 las reglas que el inventor de las bases de datos relacionales (Edgar F. Codd) propuso para describir a una base de datos relacional:

  • Regla Cero: El sistema debe ser relacional […] Ese sistema debe utilizar sus facilidades relacionales (exclusivamente) para manejar la base de datos.
  • Regla Cinco:  la regla comprensiva del sublenguaje de los datos, el sistema debe soportar por lo menos un lenguaje relacional que….

Por lo tanto, no se puede decir que una sistema de administración de base de datos sea relacional, a menos que funcione a partir de principios relacionales y utilice un lenguage que permita explotar completamente estos principios.

Así las cosas, de algún modo terminamos con bases de datos como Oracle, SqlServer o hasta Postgresql o MySql, que presumen de ser relacionales, pero que, al no contar un un lenguage verdaderamente relacional para trabajar con ellas, en realidad no son relacionales, son “pseudo-relacionales”, aparentan ser relacionales, pero están incompletas.

La primera (y hasta el momento quizá la única) base de datos relacional construida por una gran empresa (IBM) fue el Business System 12,  en 1982, quizá a algunos les sorprenderá saber, que dicha base de datos no usaba SQL como su lenguage de consultas. Utilizaba un lenguage mucho mas avanzado y completo (muy parecido al que implementa ahora Rel) pero desgraciadamente, como muy a menudo sucede en nuestra industria, la que dominaría el mercado por los siguientes 30 años no fue la mejor propuesta tecnológica, si no la mejor propuesta de mercadotécnica de Oracle la que se encargaría de popularizar al muy inferior lenguaje SQL (e influenciaría negativamente a los lenguajes de consultas que irían apareciendo posteriormente) .

De vuelta a la practica: Variables Relacionales

Pero volvamos a la practica, las relvar, un termino creado por C. J. Date, es una abreviatura para el concepto de “relation variable” o en español “variable relacional o variable de relación”.  Que es una variable relacional? Bueno, una variable relacional, es una variable que se refiere a una relación, en el modelo relacional, una relación esta definida como una estructura de datos que consiste de un encabezado y una serie no ordenada de tuplas que comparten el mismo tipo… es  lo que comúnmente llamamos “tabla” o “vista” en SQL. Así pues, una relvar es una variable que representa a una relación.

En Rel, podemos, por ejemplo, escribir lo siguiente:

VAR USUARIOS BASE RELATION
{  Nombre CHAR

}

KEY { Nombre } ;

VAR RELACIONES_USUARIOS  BASE RELATION
{  NombreUsuarioOrigen CHAR,

NombreUsuarioDestino CHAR,

TipoRelacion CHAR
}

KEY { NombreUsuarioOrigen, NombreUsuarioDestino,TipoRelacion } ;

Eso seria el equivalente a escribir, en SQL:

CREATE TABLE PROYECTOS(

Nombre varchar(MAX) NOT NULL

PRIMARY KEY (Nombre)

)

CREATE TABLE RELACIONES_USUARIOS (

NombreUsuarioOrigen varchar(MAX) NOT NULL,

NombreUsuarioDestino varchar(MAX) NOT NULL,

TipoRelacion varchar(MAX) NOT NULL

PRIMARY KEY (NombreUsuarioOrigen,NombreUsuarioDestino, TipoRelacion )

)

en ambos casos, estamos definiendo 2 relaciones (solo que en las bases de datos pseudo-relacionales, a las relaciones base, se le conoce como tablas). Una relación base es aquella que es parte de la base de datos, por lo que es persistente y global, si omitiéramos la palabra “base” tendríamos como resultado una variable local.

Un momento ¿Como que una variable local?. Si, en una base de datos verdaderamente relacional, la relvar pueden ser globales, o locales, podemos crear una relvar para un trabajo determinado dentro de un algoritmo, y dejar que se desaparezca por si misma al final… parecido a una tabla temporal… pero al mismo tiempo muy diferente (y mas poderoso).

Las relvars y la cerradura matemática

En matemáticas, existe el concepto de cerradura, en el que se dice que un un conjunto es cerrado cuando al efectuarse una determinada operación sobre algunos de los miembros del conjunto el resultado es también un miembro del mismo conjunto.

Por ejemplo, el conjunto de los números reales contiene al 3 y al 7. Si sumamos (3+7) el resultado es 10, que también es un numero real. por otro lado, si tomamos al conjunto de los números enteros, otra ves al 3 y al 7, y efectuamos una división: (7/3) el resultado (2.333) no es un numero entero, por que para la operación división, sobre el conjunto de los números enteros, no hay cerradura.

¿Por que es importante la cerradura? Bueno, por que es uno de los principios que nos permite entender a las matemáticas, y si no lo tomamos en cuenta al implementar estas operaciones en la computadora, podríamos estarnos complicando la vida gratuitamente. Imaginemos, por ejemplo, que el inventor de SQL hubiera programado al tipo Integer de Java, y que hubiera cometido el mismo error que cometió en SQL: olvidar a la cerradura.

En nuestro lenguaje Java sin cerraduras en los enteros , no podríamos escribir:

Integer x = new Integer(5);
Integer y = new Integer(6);
Integer z = x.add(y);

Tendríamos que escribir:

Integer x = new Integer(5);
Integer y = new Integer(6);
IntegerResult z = x.add(y);

No parece un gran problema verdad? Pero resulta que la operación add (suma) solo puede realizarse entre enteros, así que en nuestro Java sin cerraduras no podemos hacer esto:

Integer x = new Integer(5);
Integer y = new Integer(6);

Integer w = new Integer(2);

IntegerResult z = x.add(y);

IntegerResult v= z.add(w); //Error, z no tiene un metodo “add”

Pero sin embargo, si Java estuviera diseñado del mismo inconsistente modo que SQL, seria valido escribir:

IntegerResult v = x.add(y).add(w);

Suena como una locura no? Por que si es valido si lo pongo en una misma expresión pero no si lo quiero partir en variables? bueno, pues eso es lo que pasa en SQL, como no tiene cerradura en expresiones entre relaciones, no podemos guardar el resultado intermedio de una operación relacional para aplicarle mas operadores relacionales : Que beneficio tiene este comportamiento esquizofrénico? Ninguno, fue simplemente una falta de visión por parte del diseñador de SQL, que nos ha complicado la vida por 30 años. Asi pues, en Rel podemos escribir:

OPERATOR USUARIOS_CON_NOMBRE(NombreABuscar CHAR) RETURNS RELATION {Nombre CHAR};
   RETURN USUARIOS WHERE Nombre = NombreABuscar;
END OPERATOR;

y utilizarlo luego en un query:

USUARIOS_CON_NOMBRE('Juan')  RENAME (Nombre AS NombreUsuarioOrigen) JOIN RELACIONES_USUARIOS

En TSQL (el dialecto SQL de Microsoft)  puede hacerse algo parecido con las UDF que retornan tablas, en PL/SQL (el dialecto de Oracle), empezó a poderse hacer algo parecido a partir de la versión 9i, pero la sintaxis en Oracle resulta, en mi opinión, bastante latosa (hay que definir un Oracle Type, y hacer casting) (y muy distinta a la de TSQL (no es necesario sin definir un Type ni hacer casting), así que no hay portabilidad entre Oracle y MSSQL).  En PostgreSQL igual se puede, pero igual, con otra sintaxis distinta. Otras bases de datos SQL no cuentan con esta capacidad (Creo que MySQL no lo soporta, aunque parece que alguien esta tratando de ponérselo), lo cual limita mucho su uso… aunque resulta interesante que conforme voy escribiendo este blog post me doy cuenta que las bases de datos SQL van tratando de disminuir sus limitaciones conforme pasan los años

Virtual Relvars, Literal Relvars

En Rel, podemos definir una “relvar virtual” derivada de un otra relvar:

VAR U VIRTUAL (USUARIOS);

En este caso, U y USUARIOS son básicamente idénticas, pero podríamos definir a P como un subconjunto de USUARIOS con ciertas características:

VAR U VIRTUAL (USUARIOS WHERE NOMBRE = 'JUAN');

Si ya han trabajado con SQL, esto les recordara la creación de una vista:

CREATE VIEW U AS (SELECT USUARIOS WHERE NOMBRE = 'JUAN')

Una característica importante (y la razón por las que nos referimos ellas como relvars) de una base de datos verdaderamente relacional, es que al usar una “relvar virtual”, debemos poder tratarla exactamente como si no  fuera “base relvar”, es decir, debe una vista debe ser indistinguible de una tabla desde la perspectiva del que la usa (se le pueden hacer inserts, updates, deletes, y hasta ponerle restricciones de integridad   propias o con otras relvar (virtuales o no)).

Podemos inclusive crear una relacion "literal" (en Java podemos tener int X, una variable entera, y "5" una literal entera, en SQL, hasta donde se, no hay soporte para literales relacionales, o si?):

RELATION {
        TUPLE {NombreUsuarioOrigen 'Jose', NombreUsuarioDestino 'Pedro', TipoRelacion 'Amigo'},
        TUPLE {NombreUsuarioOrigen 'Juan', NombreUsuarioDestino 'Alfredo', TipoRelacion 'Amigo'}
 }

y hacer operaciones con ella (aqui estamos filtrando por los que se llame Juan, pero igual podriamos hacer un JOIN con una base relvar, o con otra literal):

RELATION {
        TUPLE {NombreUsuarioOrigen 'Jose', NombreUsuarioDestino 'Pedro', TipoRelacion 'Amigo'},
        TUPLE {NombreUsuarioOrigen 'Juan', NombreUsuarioDestino 'Alfredo', TipoRelacion 'Amigo'}
 } where NombreUsuarioOrigen = 'Juan'

JOIN entre 2 literales:

RELATION {
        TUPLE {Nombre 'Juan'},
        TUPLE {Nombre 'Pedro'},
        TUPLE {Nombre 'Alberto'},
        TUPLE {Nombre 'Jose'},
        TUPLE {Nombre 'Alfredo'},
        TUPLE {Nombre 'Roberto'}
 } RENAME (Nombre AS NombreUsuarioOrigen)
JOIN
RELATION {
        TUPLE {NombreUsuarioOrigen 'Jose', NombreUsuarioDestino 'Pedro', TipoRelacion 'Amigo'},
        TUPLE {NombreUsuarioOrigen 'Juan', NombreUsuarioDestino 'Alfredo', TipoRelacion 'Amigo'}
 }

Como ven, una base de datos verdaderamente relacional nos permite jugar con relaciones del mismo modo que en Java jugaríamos con Enteros, Cadenas, Arreglos, o Diccionarios.

Restricciones

Habrán notado quizá, que las 2 relvars que definí (USUARIOS,RELACIONES_USUARIOS) no establecí ninguna restricción de integridad, (también conocidas como “relaciones” en el mundo ORMs), definir restricciones es importante, por que así se pueden evitar errores, como por ejemplo, decir que “Juan” es amigo de “Rodrigo” no habiendo ningun “Rodrigo” registrado en la base de datos. Pero veamos un ejemplo:

Primero vamos a insertar unos cuantos registro en la tabla de usuarios:

INSERT USUARIOS  RELATION {
        TUPLE {Nombre 'Juan'},
        TUPLE {Nombre 'Pedro'},
        TUPLE {Nombre 'Alberto'},
        TUPLE {Nombre 'Jose'},
        TUPLE {Nombre 'Alfredo'},
        TUPLE {Nombre 'Roberto'}
 };

luego, establezcamos algunas amistades:

INSERT RELACIONES_USUARIOS  RELATION {
        TUPLE {NombreUsuarioOrigen 'Jose', NombreUsuarioDestino 'Pedro', TipoRelacion 'Amigo'},
        TUPLE {NombreUsuarioOrigen 'Juan', NombreUsuarioDestino 'Alfredo', TipoRelacion 'Amigo'}
 };

Notese que en este punto, bien podríamos hacer esto: INSERT RELACIONES_USUARIOS RELATION { TUPLE {NombreUsuarioOrigen 'Juan', NombreUsuarioDestino 'Rodrigo', TipoRelacion 'Amigo'} }; Y la base de datos no nos lo impediría... ¿como podemos evitar que este tipo de datos incongruentes entren en nuestra base de datos? Y que pasa con los tipos de relación? es 'Amigo' el único aceptable? Puede haber mas? cuales serian? como controlo eso?

Eso lo veremos en la Parte III

style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-5164839828746352"
data-ad-slot="7563230308">