Help & Manual authoring tool
Tecno Soft Solutions. Reseller autorizado de Symbol, líder mundial en captura de códigos de barras.
Este artículo muestra como aplicar la ingeniería inversa a una base de datos es poder obtener un modelo entidad–relación partir de una base de datos ya implementada.

Ingeniería inversa de base de datos

Copyright © 2003 Alejandro Narancio

Este artículo fue primero publicado en el Boletín para Desarrolladores de Software

EurekaLog - Capture y registre cada excepción!

Índice

KnowledgeBase Vortex 2.9

Introducción

Hace algún tiempo se me encargó realizar una aplicación que aplicara ingeniería inversa a una base de datos. La idea principal de aplicar ingeniería inversa a una base de datos es poder obtener un modelo entidad–relación partir de una base de datos ya implementada.

En una primera instancia apenas conocía la definición de lo que se me encargaba. Por lo tanto comencé a buscar información al respecto (libros, revistas, Internet, etc.). El problema fue que lo único que encontré sobre el tema fueron definiciones (cosa que yo ya tenía), no existiendo ningún tipo de análisis acerca de como realizar esta tarea (ni siquiera en inglés). Por esta razón decidí escribir el análisis que realicé sobre el tema, dado que tal vez sirva aunque sea de guía inicial para aquellas personas que se enfrenten al mismo problema.

En este texto partiré de la base que el lector conoce los conceptos del modelo relacional y del modelo entidad–relación planteado por Chen, pero de todas formas haré una breve reseña sobre estos dos en las próximas secciones. Además recomiendo que el lector posea conocimientos de normalización de base de datos.

En mi caso, trabajé con Delphi y Oracle 8i Lite, pero de todas formas mi idea es que tras leer el análisis se pueda realizar en cualquier lenguaje y con cualquier base de datos.

Modelo relacional

En esta sección intentaré dar un panorama general acerca del modelo relacional. De todas formas recomiendo que consulten material específico sobre el tema, como ser el libro de C. J. Date o que busquen en Internet. Aquí les suministro algunas direcciones:

El modelo relacional tiene tres partes principales, que tienen que ver con la estructura de datos, la integridad de los datos y la manipulación de datos. Cada una de las partes que nombramos anteriormente tiene su propia terminología especial.

En el caso de la estructura de datos, los términos estructurales más importantes son las relaciones. Una relación se encuentra compuesta por un conjunto de tuplas (cuerpo de la relación) y un conjunto de pares atributo–dominio (cabecera de la relación) y podría llegar a ser representada físicamente por una tabla. Además cada relación posee su clave primaria, una cardinalidad y un grado asociado a ella.

La cardinalidad de una relación se encuentra dada por el número de tuplas que contiene la relación (en el caso de que se represente la relación como una tabla, entonces una tupla es el equivalente a una fila de la tabla). La máxima cardinalidad posible para una relación es el producto cartesiano de todos los dominios que componen la cabecera de la relación.

El grado es el número de atributos que contiene una relación (en el caso de que nuevamente consideremos a la relación como una tabla, el grado sería el número de columnas de la misma).

Un dominio es un conjunto de valores atómicos que nos define el conjunto de valores válidos para un atributo.

Dominios

Un dominio no es más que un tipo de datos (para abreviar, un tipo), y puede llegar a ser un tipo definido por el propio sistema (integer, char, etc.), o un tipo definido por el propio usuario.

Un tipo no es más que un conjunto de valores válidos. Por ejemplo, el tipo integer es el conjunto de todos los enteros posibles. Además, junto con la noción de un tipo dado está asociada la noción de los operadores válidos que se pueden aplicar legalmente a valores de ese tipo, es decir, se puede operar exclusivamente sobre valores de ese tipo por medio de operadores definidos para el mismo.

Propiedades de las relaciones

Las relaciones poseen ciertas propiedades que se desprenden directamente de su propia definición.

  • No existen tuplas duplicadas

    Debido a que el cuerpo de la relación es un conjunto matemático (de tuplas); estos no admiten que existan valores duplicados.

    Esta primera propiedad sirve para ilustrar el punto de que, en general, una relación y una tabla no son lo mismo, ya que una tabla en sí misma puede contener filas duplicadas, mientras que una relación no admite bajo ningún concepto tuplas duplicadas.

  • Las tuplas están en desorden, de arriba hacia abajo

    Al igual que la propiedad anterior, ésta surge del hecho que el cuerpo de la relación es un conjunto matemático: en matemáticas, los conjuntos no están ordenados.

    Por ejemplo, dada una relación con un cierto número de tuplas (por ejemplo, con 10 tuplas) no podemos referirnos a ellas por medio de un índice, como ser la quinta tupla, etc. Esto se debe a que no existe el concepto de direccionamiento posicional.

    Como se mencionó en la propiedad anterior, esta segunda propiedad sirve también para ilustrar la idea de que una relación y una tabla no son lo mismo, ya que las filas de una tabla obviamente tienen un ordenamiento de arriba hacia abajo, mientras que las tuplas de una relación no lo tienen.

  • Los atributos están en desorden, de izquierda a derecha

    Esta propiedad surge del hecho de que el encabezado de una relación también es un conjunto (de atributos). Por esta razón no existe algo como el "primer atributo", etc. Por lo tanto, siempre se hace referencia a los atributos por nombre y nunca por posición. Esto tiene como resultado la reducción de errores y una programación más clara.

    Nuevamente esta propiedad marca diferencias entre una relación y una tabla, por la sencilla razón que en una tabla las columnas se encuentran ordenadas, y se pueden acceder a ellas a través de posiciones.

  • Cada tupla contiene exactamente un valor para cada atributo

    Esta propiedad surge inmediatamente de la definición de una tupla: una tupla es un conjunto de n componentes o pares ordenados de la forma Ai:vi (i = 1,2, ..., n). Se dice que una relación que satisface esta propiedad se encuentra normalizada o -lo que es equivalente- que está en la primera forma normal.

Integridad

El término integridad se refiere a exactitud o corrección de los datos en la base de datos.

Restricciones de tipo

Está restricción especifica los valores válidos para un tipo dado.

En esencia, una restricción de tipo es (o es equivalente de manera lógica a) una sola enumeración de los valores válidos del tipo. Por lo tanto, una restricción de tipo es básicamente sólo una especificación de los valores que conforman el tipo en cuestión.

A está restricción se la denomina también restricción de dominio, y nos dice que los dominios deben ser atómicos, o sea, deben ser una unidad mínima de información.

Restricciones de atributo

Especifica el valor válido para un atributo dado. Es sólo una declaración para que un atributo especifico sea de un tipo particular. Por esta razón, una restricción de atributo puede ser eliminada únicamente mediante la eliminación del propio atributo.

Restricciones de entidades

Ningún componente de una clave primaria de una relación puede ser nulo. El valor nulo es un valor indefinido, y la clave primaria de una relación identifica de forma única y mínima a una sola tupla de la relación. Por ende, si algún componente de la clave primaria pudiese ser nulo, entonces dicha clave primaria no sería mínima, porque nos estaría diciendo que ese atributo no es necesario para identificar a una tupla dada. Por está razón, si existieran componentes nulos en una clave primaria, esta no identificaría a ninguna tupla.

Restricciones de referencia

Con esta restricción nos referirnos a las relaciones existentes en el modelo relacional. Nos dice que no pueden existir valores de clave ajena (foránea) sin una concordancia, es decir, que dicha clave foránea debe contener un valor que exista en la relación a la cual hace referencia. Además esta restricción nos impone que una clave foránea es o toda no nula o toda nula (con esto se representa la totalidad y la parcialidad de la relación).

Modelo entidad-relación

Este es un modelo conceptual de datos de alto nivel muy utilizado introducido por Peter Chen en 1976, que sirve para la representación de estructuras de información, no conteniendo un lenguaje para representación de manipulaciones de datos

Este modelo y sus variaciones se emplean a menudo en el diseño conceptual de aplicaciones de bases de datos. El objetivo principal del diseño conceptual es crear un esquema conceptual de alto nivel, independiente del DBMS (Data Base Managment System), partiendo de especificaciones de requerimientos que describan la realidad.

Al igual que otros problemas en la informática, dada la complejidad que se presenta en el diseño de una base de datos, éste se divide en subproblemas o etapas independientes que se pueden resolver por separado usando métodos y técnicas específicas. El diseño de base de datos se divide en tres grandes fases de diseño, con una fase posterior a estas de recolección y análisis de requerimientos.

  1. Diseño conceptual. Una vez recabados y analizados todos los requerimientos, el siguiente paso es crear un esquema conceptual para la base de datos. Éste es una descripción concisa de los requerimientos de información de los usuarios, y contiene descripciones detalladas de los tipos de datos, las relaciones y las restricciones.

  2. Diseño Lógico. Esta fase consiste en implementar una descripción de la estructura de la base de datos que puede procesar el software de DBMS, esto es conocido como esquema lógico.

  3. Diseño Físico. Este es paso final durante el cual se especifican las estructuras de almacenamiento internas y la organización de los archivos de la base de datos. Hay una retroalimentación entre el diseño físico y el lógico, porque las decisiones tomadas durante el diseño físico para mejorar el rendimiento pueden afectar las estructuras del esquema lógico.

Una vez completo el diseño físico de la base de datos, los diseños lógico y físico se expresan mediante un lenguaje de definición de datos (DDL) del DBMS a usar. De esta forma la base de datos puede ser cargada y probada, y más aún, las aplicaciones que usan la base de datos se pueden diseñar y probar completamente.

El modelo ER describe los datos como entidades, relaciones y atributos. Una entidad se puede definir como un elemento del mundo real con existencia independiente. Los atributos son propiedades específicas que describen las entidades. Por último podemos definir las relaciones como conjunto de asociaciones entre entidades.

Junto con el modelo Entidad-Relación, Chen también presentó el concepto de Diagrama de Entidad–Relación (DER). Los Diagramas Entidad–Relación constituyen una técnica para representar la estructura lógica de una base de datos en forma de gráficos. Éstos proporcionan un medio sencillo y de fácil comprensión para comunicar las características sobresalientes de cualquier base de datos dada. A continuación se presentarán algunos conceptos básicos para elaborar un DER (de todas formas, los DER pueden ser representados de diversas maneras).

Entidades y atributos

Las entidades se representarán por medio de rectángulos y los nombres de éstas serán en plural y empezarán siempre con mayúscula. Los atributos se escriben alrededor de la entidad, y la clave primaria va subrayada, como se puede ver en la figura.

Relaciones

Las relaciones se representan por medio de rombos y se unen con las entidades participantes por medio de aristas.

Además, deben ser nombradas significativamente.

Sobre las aristas se indica la cardinalidad de la relación (1-1, 1-N, N-1, N-N).

En la unión entre la arista que une la relación con alguna de las entidades participantes de la relación se puede indicar la totalidad o parcialidad de la relación mediante la existencia o no de un punto (el punto indica totalidad mientras que su ausencia indica parcialidad).

Estos conceptos quedarán más claros luego de ver el ejemplo siguiente:

Cuando decimos que la relación Asignaciones es N-1 queremos decir que "un empleado no puede estar asignado a más de un departamento" y que "un departamento puede contener muchos (N) empleados". Cuando decimos que la relación Asignaciones es total del lado de Empleados queremos decir que "todo empleado tiene asignado por lo menos un departamento".

Para resumir, podemos decir que la cardinalidad de una relación denota el máximo y la totalidad y parcialidad un mínimo.

Vale la pena aclarar que los valores de cardinalidad y totalidad no tienen porque ser N o 1, sino que pueden ser cualquier valor numérico (si se quiere indicar un mínimo específico de totalidad debe ir por debajo de la arista, sino se toma el valor por omisión 1).

Las relaciones también pueden tener atributos y se representan de la misma forma que los atributos de las entidades.

También tenemos un caso particular en el que si R es una relación que relaciona elementos de un conjunto de entidades E a elementos de ese mismo conjunto E, R se denomina relación recursiva. Para que éstas queden más claras, se distingue el rol que cada elemento del conjunto de entidades tiene en la relación agregándoseles un rótulo en cada una de las aristas, como se puede apreciar en el ejemplo.

Agregaciones

Consiste en considerar un conjunto de relaciones y sus conjuntos de entidades como un conjunto de entidades "agregando" toda la información, relacionando esa agregación a otro conjunto de entidades.

Como se puede apreciar en la figura, la agregación se representa encerrando la relación y las entidades participantes en un rectángulo.

Categorizaciones

Existen muchos casos prácticos en que un conjunto de entidades representa elementos del mundo real que se subdividen en categorías con atributos parcialmente distintos.

Las categorizaciones pueden tener nombre y se representan mediante triángulos.

Definiciones sobre ingeniería inversa de base de datos

La Ingeniería Inversa de Bases de Datos:

Es el conjunto de técnicas que permite la obtención de una representación conceptual de un esquema de base de datos a partir de su codificación.

Aplicaciones:

Sus aplicaciones son múltiples. Re-documentar, reconstruir y/o actualizar documentación perdida o inexistente de bases de datos, servir como pivote en un proceso de migración de datos, y ayudar en la exploración y extracción de datos en bases poco documentadas.

Análisis de la implementación

Ahora comenzaremos a realizar el análisis por el cual obtendremos -como ya hemos dicho más de una vez- el modelo conceptual de una base de datos a partir de un modelo físico.

Como ya he dicho anteriormente, yo implementé esta aplicación en Delphi, con un Oracle Server 8i Lite, por lo tanto los ejemplos que realizaré serán basándome en que utilizo dichos productos. De todas formas, el análisis es el mismo a seguir independientemente del lenguaje o base de datos que utilicemos.

Obtener información de la estructura de la base de datos

Lo primero que debemos hacer es obtener toda la información posible de la estructura de la base de datos (no de los datos que contiene),es decir, nombre de las tablas, atributos de las tablas, etc.

Dicha información se encuentra almacenada en el catálogo de la base de datos (el cual se consulta fácilmente utilizando SQL). La información que obtendremos a partir del catálogo la debemos almacenar en algún lado (yo en particular me creé una serie de clases que permitían almacenar toda la información y además a dichas clases les agregue cierta funcionalidad que me permitía manejar fácilmente la información almacenada en ellas).

Lo primero que haremos será obtener todas las tablas que componen la base de datos. Para realizar esto debemos efectuar una consulta SQL. En dicha consulta no sólo obtendremos los nombres de las tablas, sino que también obtendremos los atributos que componen dicha tabla con sus características más generales (tipo de dato, y si admite valores nulos), es decir, que aún no sabemos que atributos componen la clave primaria o alguna clave foránea.

La consulta SQL que utilice es la siguiente:

SELECT at.table_name, attc.column_name, attc._data_type, attc.nullable
FROM all_tables at, all_tab_columns attc
WHERE at.table_name = attc.table_name

El resultado de dicha consulta será el siguiente: por cada fila habrán cuatro columnas. Las columnas significan lo siguiente: nombre de la tabla, nombre del atributo, tipo de dato del atributo y si el atributo puede ser nulo. Por lo tanto, cada tabla tendrá tantas filas en el resultado de la consulta como atributos posea.

Una vez realizada esta consulta procederemos a guardarla en nuestras estructuras de almacenamiento. Una vez hecho esto estamos en condiciones de analizar cuales atributos de las tablas corresponden a la clave primaria, cuales son claves foráneas y cuales son claves únicas (que en el modelo de normalización serían las claves candidatas).

Lo primero que haremos será obtener aquellos atributos que componen la clave primaria de una tabla dada. La siguiente consulta se debería realizar para cada tabla existente en la base de datos, cambiando en la siguiente consulta NombreTabla por el nombre de la tabla que estamos consultando (a partir de este momento, cada vez que se coloque NombreTabla se entenderá que es la tabla que nos encontramos analizando). Aquí va la consulta SQL realizada:

SELECT column_name
FROM all_constraints ac, all_cons_columns acc
WHERE ac.table_name = 'NombreTabla'
  AND ac.constraint_type = 'P'
  AND ac.constraint_name = acc.constraint_name
ORDER BY acc.position;

El resultado de esta consulta es una fila para cada atributo que forma parte de la clave primaria. Dichos atributos se desplegarán en orden ascendente según su posición, para así poder ingresarlos en el orden por el cual fueron definidos.

A está altura ya tenemos cargados los nombre de las tablas y sus atributos, con sus respectivos tipo de datos, e identificados los atributos que conforman a la clave primaria.

A continuación obtendremos los atributos que forman las claves foráneas de una tabla, y las tablas a las cuales hace referencia dicha clave foránea perteneciente a una determinada tabla, que llamaremos nuevamente NombreTabla.

SELECT ac.constraint_name, column_name, r_constraint_name
FROM all_constraints ac, all_cons_columns acc
WHERE ac.table_name = 'NombreTabla'
  AND ac.constraint_type = 'R'
  AND ac.constraint_name = acc.constraint_name
ORDER BY acc.position;

Como resultado obtenemos una fila por cada atributo que compone a una clave foránea. Cada constraint (clave foránea en este caso) tendrá tantas filas como atributos los compongan. Por cada columna tenemos la siguiente información en el siguiente orden: nombre del constraint, nombre del atributo y nombre del constraint al cual hace referencia.

A partir de los constraints a los cuales se hacen referencia, se puede obtener fácilmente a que tabla pertenecen por medio de la siguiente consulta:

SELECT table_name
FROM all_constraints
WHERE constraint_name = 'NombreConstraint'

Con la consulta anterior obtuvimos a que tabla pertenece el constraint NombeConstraint y por lo tanto, si una clave foránea hace referencia al constraint NombreConstraint, entonces ahora sabemos a que tabla hace referencia dicha clave foránea.

Finalmente, para la carga de datos nos queda únicamente averiguar cuales son los atributos que componen a las claves únicas. Para esto realizamos la siguiente consulta:

SELECT ac.constraint_name, column_name
FROM all_constraints ac, all_cons_columns acc
WHERE ac.table_name = 'NombreTabla'
  AND ac.constraint_type = 'U'
  AND ac.constraint_name = acc.constraint_name
ORDER BY acc.position;

La consulta anterior nos devuelve todas las claves únicas que existen en una tabla. Cada clave única tendrá tantas filas en el resultado de la consulta como atributos la compongan. El significado de las columnas es el siguiente: nombre del constraint (o sea, de la clave única en este caso) y nombre del atributo.

Análisis de las tablas

A continuación presentaré como determinar que representación conceptual tiene una tabla dada. Es decir, por ejemplo, una tabla puede ser considerada una entidad, una relación binaria, una relación ternaria, una categorización, etc.

El análisis puede ser encarado de dos formas completamente distintas. Una es por medio de consultas SQL, es decir, que se realice una consulta SQL y en función de los resultados determinar por ejemplo si una tabla corresponde a una entidad o a una relación, o por ejemplo determinar si una tabla corresponde a una relación binaria o ternaria, etc.

El problema con esto es que nuestra aplicación será dependiente de la base de datos que estemos utilizando, y por ende debemos escribir todas las consultas SQL para cada uno de los motores de base de datos a los que nuestra aplicación les realice ingeniería inversa.

La otra posibilidad es utilizar la información que tenemos almacenada en nuestras estructuras. Con esta información es posible determinar casi cualquier caso (digo casi porque como veremos más adelante existen algunas circunstancias en las que no podremos determinar a que modelo conceptual corresponde).

Las únicas consultas que deberemos escribir para cada motor de base de datos son aquellas para extraer la información sobre las estructuras, pero esto no es tan complicado debido a que apenas son cinco consultas. En mi análisis utilizaré la segunda opción debido a que obviamente es mucho más flexible que la primera.

Para el análisis, al igual que hicimos a la hora de obtener la información de la estructura de la base de datos, nos crearemos un conjunto de estructuras de almacenamiento en las cuales iremos almacenando los datos que obtendremos del análisis. Yo en particular me creé las siguientes estructuras, nuevamente utilizando clases: entidades, relaciones, agregaciones y categorizaciones. En entidades obviamente almaceno aquellas tablas en que sean entidades, en relaciones almaceno el nombre de la relación, cardinalidades, totalidad y parcialidad y todas las tablas que relaciona, en agregación almaceno el nombre de la agregación junto con todas las estructuras que relaciona y finalmente en categorizaciones almaceno la tabla que corresponde a la categorización y su madre.

En general, el siguiente análisis debe ser realizado por todas las tablas. Como guía, a continuación presento un diagrama de flujo, que es el que se debe seguir a la hora de analizar una tabla. Es decir, a una tabla dada se le realizarán ciertas pruebas y en función de los resultados de dichas pruebas decidiremos que 'camino' del diagrama de flujo seguir.

A continuación presento el diagrama de árbol que me ha servido de ayuda a la hora de realizar el análisis.

Determinar si una tabla corresponde a una entidad o a una relación

Lo primero que debemos realizar en el proceso del análisis es determinar si el modelo conceptual de una tabla corresponde a una entidad o a una relación.

Para realizar dicho análisis, intentaremos probar distintos casos, mediante los cuales podremos ir descartando las diferentes opciones que poseemos.

Determinar si corresponde a una entidad aislada

Tal vez el término 'aislada' no es el más adecuado, debido a que en un modelo relacional bien hecho, muy difícilmente existan tablas completatamente aisladas. En este análisis nos referimos a entidades aisladas cuando una tabla no posee claves foráneas a otras tablas. Mediante el análisis de esta tabla no podemos saber a priori las relaciones en las que participa dicha tabla, pero sí se podrá determinar más adelante en nuestro análisis. Por lo tanto no es una entidad aislada, sino que más bien es una potencial entidad aislada, pero no lo sabremos hasta finalizar el análisis de todas las tablas.

Determinar si una tabla corresponde a un entidad aislada es muy sencillo, lo único que debemos hacer es fijarnos si dicha tabla posee claves foráneas. En el caso de que posea estamos seguros de que no es una entidad aislada y podemos proseguir con el análisis de la tabla, pero si se diera el caso que no posee ninguna clave foránea, entonces estamos seguros que corresponde a una entidad aislada, por lo que podemos agregar dicha tabla a nuestra estructura de almacenamiento entidades y pasar a analizar la siguiente tabla.

Determinar si corresponde a una categorización

Las categorizaciones se caracterizan por lo siguiente: toda la clave primaria de una tabla 'hija' forma una (y solo una) clave foránea a la tabla 'madre'.

Si hemos llegado a este punto sabemos que la tabla posee por lo menos una clave foránea (por dicha razón no es considerada una entidad aislada). Lo primero que debemos hacer es fijarnos si los atributos que componen a la clave primaria de la tabla componen a su vez una clave foránea. Con esto quiero decir que los atributos que componen la clave primaria NO componen a más de una clave foránea (la razón por la cual repito tanto este punto, es porque esto es fundamental a la hora de hablar de categorizaciones). En el caso que los atributos que componen la clave primaria no compongan ninguna clave foránea, o que compongan a más de una clave foránea, estamos seguros que no nos encontramos frente a una categorización (es más, como veremos más adelante, si los atributos que componen la clave primaria de la tabla, componen a su vez a más de una clave foránea, entonces estamos seguros que nos encontramos en un caso en donde la representación conceptual de la tabla es una relación y no una entidad).

A continuación plantearemos un ejemplo sencillo de categorización mediante el uso de tres tablas: empleados, gerentes y secretarias. La estructura física de las tres tablas es la siguiente:

Empleados Gerentes Secretarias
Número_Empleado (PK) Número_Empleado (PKFK) Número_Empleado(PKFK)

El atributo Número_Empleado, tanto en la tabla Gerentes como en la tabla Secretarias, forma una clave foránea a la tabla Empleados.

Debido a que tanto la tabla Gerentes como la tabla Secretarias no poseen más claves foráneas, deducimos instantáneamente que no es una tabla que represente una relación, sino que existe una categorización. Por lo tanto, la representación sería la siguiente:

Como dijimos, este es un caso extremadamente sencillo, pero en el análisis de las categorizaciones puede existir un caso particular en el cual no sepamos que quiso representar quien haya diseñado la base de datos.

Imaginemos el siguiente caso:

Empleados Gerentes Secretarias
Número_Empleado (PK) Número_Empleado (PKFK) Número_Empleado(PKFK)
Número_Computadora(FK)

Hemos agregado un nuevo atributo a la tabla Secretarias. Dicho atributo (Número_Computadora) es una clave foránea a una tabla denominada Computadoras. Si se nos diera este caso debemos realizar un análisis más profundo para poder determinar si la tabla Secretarias pertenece a una categorización, debido a que la representación conceptual de esta tabla podría ser cualquiera de las siguientes:

Caso 1:

Caso 2:

Como notará, son representaciones completamente diferentes. En la primera Secretarias forma parte de una categorización, y en la segunda Secretarias es considerada una relación entre Empleados y Computadoras, con cardinalidades N–1 o 1–1.

En ocasiones es posible poder diferenciar entre los dos casos. La única forma de hacerlo es examinando el atributo Número_Computadora que pertenece a la tabla Secretarias y que hace referencia a la tabla Computadoras: si dicho atributo admite valores nulos, estamos completamente seguros que nos encontramos en el primer caso y no en el segundo. Esto es debido a que si Secretarias fuese una tabla que representa una relación entre Empleados y Computadoras, el atributo Número_Computadora NO podría aceptar valores nulos, debido a que por definición, las relaciones binarias son pares ordenados.

Si se nos plantea el caso de que el atributo Número_Computadora perteneciente a la tabla Secretarias no admite valores nulos, es imposible diferenciar entre los dos casos que planteamos anteriormente, por lo tanto debemos adoptar criterios para poder diferenciar entre ellos (por ejemplo, valores por omisión).

Una vez terminada esta parte del análisis sabemos si la tabla pertenece a una categorización o no, si perteneciera a una categorización la almaceno en mis estructuras de almacenamiento, y analizo el resto de las claves foráneas que posee la tabla como si se tratase de una tabla que representa a una entidad referente.

Determinar si corresponde a una entidad referente

Con entidad referente quiero decir, que es una tabla que hace referencia a otras tablas (son las clásicas relaciones 1–N o 1–1).

Si llegamos a este punto sabemos que no nos encontramos frente a una tabla que representa a una entidad aislada (es decir, que posee por lo menos una clave foránea) y que tampoco corresponde a una categorización (por ende los atributos que componen la clave primaria de la tabla no componen ninguna clave foránea). Por lo tanto, ya estamos seguros que esta tabla es una tabla referente (es decir, que hace referencias a otras tablas), dado que tampoco puede representar una relación debido a que en una tabla que represente una relación los atributos que forman la clave primaria de la tabla deben formar también al menos una clave foránea.

Sabemos que cada clave foránea que posea la tabla representará una relación binaria (debido a que es el único tipo de relación que puede representarse sin utilizar una tabla) entre la tabla que nos encontramos analizando y la tabla a la cual hace referencia la clave foránea. Además sabemos que la cardinalidad de dicha relación es 1–1, o bien 1–N, debido a que si fuese N–N se debería haber representado por medio de una tabla. Finalmente también sabemos que la cardinalidad correspondiente a la tabla que nos encontramos analizando es 1.

Referencia 1–1 cruzada

A continuación aclararé a que me refiero con referencia 1–1 cruzada.

Nos encontramos en el caso que una tabla que representa una entidad hace referencia a otra (por lo tanto deducimos que la cardinalidad para la tabla que nos encontramos analizando es 1). Ahora, si se diera el caso de que la tabla a la se hace referencia también posee una referencia a la tabla que nos encontramos analizando, entonces nos encontramos en el caso de una relación 1–1 cruzada.

Como es lógico, para resolver este caso (es decir, para decidir si nos encontramos frente a está situación) debemos analizar por un momento la tabla a la cual hace referencia la tabla que nos encontramos analizando: en el caso que la tabla a la cual se hace referencia posea una clave foránea hacia la tabla que nos encontramos analizando, entonces podemos deducir con plena seguridad que nos encontramos en frente de una relación 1–1 cruzada.

Este es en el único caso en el cual podremos deducir la totalidad y parcialidad en ambos lados de la relación. Esto lo haremos de la siguiente forma: en el caso de que los atributos que compongan la clave foránea admita valores nulos quiere decir que es parcial, de lo contrario es total (este análisis se debe realizar en ambas tablas, es decir, en la que nos encontramos analizando y en la que se hace referencia).

A continuación presentaré un ejemplo de una relación 1–1 cruzada. Imagínese el caso hipotético en el cual en una empresa un funcionario puede utilizar una sola computadora, y una computadora puede estar asignada a solamente un usuario.

Funcionarios Computadoras
Número_Funcionario (PK)
Computadora_Asignada (FK)
Número_Computadora (PK)
Funcionario_Asignado (FK)

En el caso anterior el atributo Computadora_Asignada en la tabla Funcionarios hace referencia a la tabla Computadoras, y el atributo Funcionario_Asignado en el tabla Computadoras hace referencia a la tabla Funcionarios. Aquí nos encontramos en un caso claro de un relación 1–1 cruzada entre las entidades Funcionarios y Computadoras.

Referencia 1–1

Ahora podría darse el caso en el cual se quisiera representar una relación 1–1, pero no utilizando una referencia cruzada, sino que utilizando una referencia simple.

Ahora imagínese el caso que planteamos en la sección anterior, pero con una pequeña variación, que planteamos a continuación:

Funcionarios Computadoras
Número_Funcionario (PK)
Computadora_Asignada (FK)
Número_Computadora (PK)

Como se habrá dado cuenta, se eliminó la referencia existente Computadoras–Funcionarios. Por lo tanto se eliminó también la referencia cruzada.

En el caso que quién diseñó la estructura de la base de datos haya querido representar una relación 1–1 no cruzada entre las tablas Funcionarios y Computadoras, debió obligatoriamente (para que no se confundiera con una relación 1–N) definir a los atributos que componen la clave foránea de la relación (en este caso, Computadora_Asignada) como únicos. Esto nos indica que un número de computadora puede aparecer solamente una vez en la tabla Funcionarios, representando de esta manera una relación 1–1.

En este último caso sólo podemos obtener la totalidad y parcialidad del lado de la entidad Funcionarios: en el caso que los atributos que componen la clave foránea admitan valores nulos será parcial y de lo contrario será total.

Referencia 1–N

El análisis de este caso es idéntico al que realizamos en la sección anterior (es decir, en Referencia 1–1), con la salvedad que los atributos que componen la clave foránea no están declarados como únicos.

En este caso, la totalidad y parcialidad de la relación se analiza de la misma forma que el caso anterior.

Con este último caso (referencia 1–N), concluimos el análisis de las entidades. Si se diera el caso que una tabla escapa a todos estos casos, entonces nos encontramos con una tabla que representa una relación.

Análisis de una tabla que representa una relación

Si llegamos a este punto estamos completamente seguros que la tabla que nos encontramos analizando corresponde a una relación, debido a que no es una entidad aislada, no es una entidad referente y tampoco es una categorización. Desde mi punto de vista, el análisis de una relación fue sin duda el más complejo debido a la cantidad de casos diferentes que existen (recuerde que en teoría una tabla podría representar una relación de N entidades, por lo tanto el número de tablas que podría llegar a relacionar es variable e infinito).

En todos los casos en los cuales una tabla representa una relación nos es imposible determinar las totalidades y parcialidades de la relación.

Si probamos que la tabla es una relación colocaremos a esta junto con todos sus datos en nuestras estructuras de almacenamiento de relaciones (por ejemplo, nombre de la relación, tablas que relaciona, cardinalidad, etc.).

Análisis de una relación binaria

Comenzaremos nuestro análisis por un caso particular de relación, la llamada "relación binaria". Este caso se podría tratar junto con las relaciones n–arias (dado que es un caso especial de éstas), pero es tan común ver este tipo de relación que decidí tratarlo especialmente.

Relación binaria 1–1

En este tipo de relación es imposible que se de una agregación. En realidad, imposible no es, pero no es demasiado lógico hacerlo. Por dicha razón pueden haber únicamente dos claves foráneas, ni más ni menos.

Para explicar este caso plantearemos la siguiente situación: dada las entidades A y B que se relacionan mediante una relación con cardinalidad 1–1, tenemos que dado un elemento de A sólo existe un elemento de B y dado un elemento de B sólo existe un elemento de A. Ahora, para representar dicha situación mediante una tabla sólo existe una forma, y es la siguiente: una de las foráneas debe ser obligatoriamente la clave primaria (digo una porque recordemos que la clave primaria determina de forma única y mínima a cualquier tupla de la relación, y debido a que queremos representar una relación 1–1), con eso representaríamos una de las cardinalidades 1 (por ejemplo, la de A), pero aún nos falta representar la segunda cardinalidad 1 (siguiendo con el ejemplo la de B). Para realizar esto último debemos hacer uso de las claves candidatas, es decir, debemos hacer que la segunda clave foránea sea a su vez clave única (con esto representaríamos que B también posee clave única).

A continuación plantearé un ejemplo para intentar clarificar este punto.

Vehículos Matrículas_Vehículos Matrículas
Número_Vehículo(PK)
Número_Matrícula(FK)
Número_Vehículo(PKFK) Número_Matrícula(PK)

Obviamente la tabla Matrículas_Vehículos intenta representar una relación entre las entidades Vehículos y Matrículas. Como vemos, Número_Vehículo es una clave foránea y a su vez es clave primaria de la tabla, por lo que deducimos que la cardinalidad de Vehículos es 1. Ahora, si queremos representar una relación binaria 1–1 debemos hacer que los atributos que componen a la otra clave foránea (en este caso Número_Matrícula) además de foráneos sean únicos en la tabla. Con esto último representaríamos que Matrículas también posee cardinalidad 1 en la relación.

A continuación presento un conjunto de tuplas para clarificar la necesidad de poseer la clave única.

Vehículos Matrículas_Vehículos Matrículas Válido
8946 Num_Veh: 8946
Num_Mat: SAB 555
SAB 555
8946 Num_Veh: 8946
Num_Mat: SAK 430
SAK 430 No
1388 Num_Veh: 1388
Num_Mat: SAK 430
SAK 430 No

Como se ve en el ejemplo de tuplas anterior, existe una necesidad de especificar el atributo Número_Matrícula como único.

En teoría deberíamos especificar las dos claves foráneas como únicas, pero debido a que la definición de clave primaria es que es única y no nula, queda implícito que si una clave foránea debe ser a su vez clave primaria, entonces dicha clave foránea también es única. Este comentario es válido para las próximas secciones.

Relación binaria N–1 / 1–N

En este caso, y al igual que en el anterior, no es lógico pensar que se pueda llegar a formar una agregación con esta relación, por lo tanto eliminamos la posibilidad de una agregación. También al igual que en el caso anterior, en este tipo de relación solo poseemos dos claves foráneas (por la precisa razón que no pueden existir agregaciones).

Para esta situación, los atributos que componen la clave foránea correspondiente a la entidad que posee cardinalidad N deben formar a su vez la clave primaria de la tabla. A diferencia de el caso anterior, los atributos que forman la clave foránea correspondiente a la otra entidad NO pueden ser declarados como únicos.

Relación binaria N–N

A diferencia de los casos anteriores, este tipo de relación sí puede formar agregaciones, y debemos hacer ciertas consideraciones antes de comenzar su análisis.

A diferencia de los casos anteriores, para representar este tipo de relación siempre se debe utilizar una tabla, y los atributos que compongan las claves foráneas correspondientes a las dos tablas que relaciona deben formar a su vez la clave primaria de la tabla.

En el caso que la clave primaria este formada por una sola clave foránea, y que a su vez no todos los atributos de dicha clave foránea formen a la clave primaria, podemos considerar que se quiere representar a una entidad no representada (es decir, que dicha entidad existe en el modelo conceptual, pero no en el físico y lógico).

Recordemos que este tipo de relación puede formar una agregación, por lo tanto puede tener hasta N claves foráneas. Por eso la clave primaria debe estar formada como máximo por dos claves foráneas.

A continuación presentaré un caso sencillo de este tipo de relación.

Alumnos Asignaturas_Alumnos Asignaturas
Número_Alumno(PK)
Número_Asignatura(PKFK)
Número_Alumno(PKFK) Número_Asignatura(PK)

Como vemos en el ejemplo anterior, la clave primaria de la tabla Asignaturas_Alumnos se encuentra formada por dos claves foráneas.

Debido a que la tabla Asignaturas_Alumnos no posee ninguna clave foránea a excepción de las que componen a la clave primaria, deducimos rápidamente que nos encontramos frente a una relación binaria N–N.

Por lo tanto, la representación conceptual de las tablas anteriores es la siguiente:

El caso de ejemplo que planteamos anteriormente ilustra un caso típico, en el cual podemos deducir sin ambigüedades la cardinalidad y tipo de relación existente, pero imagínese el siguiente caso:

Alumnos Asignaturas_Alumnos
Número_Alumno(PK) Número_Alumno (PKFK)
Número_Asignatura (PKFK)
Número_Semestre (FK)
 
Asignaturas Semestres
Número_Asignatura (PK) Número_Semestre (PK)

La tabla Asignaturas_Alumnos posee las siguientes características: la clave primaria de la tabla se compone por dos claves foráneas, pero además posee una clave foránea que no compone a la primaria. Es obvio que nos encontramos frente a una tabla que representa una relación, pero el problema es determinar el tipo de relación existente. Si nos enfrentamos a un caso similar a este, se nos pueden plantear dos posibilidades que mostramos a continuación:

Caso 1:

Caso 2:

Como notará, existe una gran diferencia entre las dos posibilidades, debido a que la primera corresponde a una relación binaria formando una agregación, pero en el segundo caso la relación es ternaria.

Está situación se plantea debido a que si una relación forma una agregación que se relaciona con otra entidad, si dicha relación (entre la agregación y la entidad) posee cardinalidades 1–1 o N–1, existe la posibilidad de que no se represente la relación por medio de una tabla.

Para poder resolver este problema sólo tenemos dos posibilidades. La primera es examinando los atributos que forman la clave foránea que no compone la clave primaria de la tabla que representa la relación y en el caso de que dichos atributos admitan valores nulos, entonces deducimos directamente que nos encontramos frente al caso de una agregación, debido a que si fuese una relación ternaria no debería admitir valores nulos. Si la primer opción falla, tenemos una ultima opción y es intentar probar una relación 1–1 cruzada entre la relación y la entidad (en nuestro ejemplo entre la tabla Asignaturas_Alumnos y Semestres) en el caso de que probemos que existe una relación 1–1 cruzada podemos decir con total seguridad que nos encontramos frente a una agregación.

Si las dos pruebas que explicamos anteriormente fallan, entonces no tenemos forma de determinar frente a que caso nos encontramos.

Análisis de una relación n–aria

Si llegamos a este punto, sabemos con certeza de que la tabla representa una relación, y que a su vez esta relación no es binaria. Por ende, nos queda sólo determinar si es o no una agregación, y en el caso que no lo sea analizar las características de la relación (cardinalidad, entidades que relaciona, etc.).

Para realizar este análisis consideraremos que una relación n–aria es una relación que relaciona N entidades, siendo N un número mayor que dos (esto lo haremos porque las binarias las analizamos en la sección anterior, pero no se debe perder de vista que una relación binaria es un caso particular de una relación n–aria). A pesar de este hecho, existen tres posibilidades bien diferenciadas en una relación n–aria, vinculadas con sus cardinalidades: la primera es que todas sus cardinalidades sean uno, la segunda es que todas sus cardinalidades sean N y finalmente que sus cardinalidades sean una mezcla entre unos y enes.

Relación n–aria con todas sus cardinalidades N

Si una tabla representa una relación n–aria con todas sus cardinalidades N, entonces sabemos con certeza de que dicha tabla no posee claves únicas para representar su cardinalidad (debido a que no necesita esto).

Distinguir este tipo de relación es sumamente fácil, debido a que para representar esta cardinalidad todas las claves foráneas que forman la relación deben formar a su vez la clave primaria de la tabla.

Ahora puede darse el caso de que se quiera representar una relación entre varias entidades, en donde una de estas entidades no se represente tanto en el modelo lógico como en el físico. No tenemos duda que es una relación n–aria con todas sus cardinalidades N, debido a que no posee claves únicas y todas las claves foráneas forman la clave primaria. Pero no todos los atributos que componen a la clave primaria son foráneos, por lo tanto deducimos que existen entidades no representadas en el modelo físico. Aquí se evaluarán dichos atributos según los criterios que nosotros impongamos (por ejemplo, cada atributo es una entidad no representada, preguntar al usuario, etc.).

A continuación planteo un ejemplo, de una relación n–aria con entidades no representadas:

Tipos_de_Movimientos Conformes Tipos_Conformes
Número_Tipo (PK) Número_Conforme (PK) Número_Tipo (PKFK)
Número_Conforme (PKFK)
Fecha (PK)

En las tablas anteriores, notamos que en la tabla Tipos_Conformes el atributo Fecha forma parte de la clave primaria de la tabla, pero no compone ninguna clave foránea, por lo tanto deducimos que es una entidad no representada (no sería lógico tener en el modelo físico una tabla con todas las fechas posibles; en cambio, en el modelo conceptual sí es útil y muchas veces necesario).

La representación conceptual de las tabla anteriormente expuestas es la siguiente:

Los casos planteados anteriormente son los más sencillos a la hora del análisis, pero como siempre se puede complicar un poquito más. Imagínese el caso de una relación ternaria con todas sus cardinalidades N que forma una agregación, que se relaciona a su vez con otra entidad mediante una cardinalidad 1–1 o N–1. A continuación planteo un ejemplo de esta situación:

Tablas Usuarios Permisos
Número_Tabla (PK) Número_Usuario(PK) Número_Permiso (PK)
 
Tablas_Usuarios_Permisos Atributos
Número_Tabla (PKFK)
Número_Usuario (PKFK)
Número_Permiso (PKFK)
Número_Atributo (FK)
Número_Atributo (PK)

Las tablas anteriores poseen dos representaciones conceptuales totalmente válidas. A continuación expongo la primer opción:

O también podría interpretarse de la siguiente forma:

Como vemos en este caso, las dos opciones son diferentes representa. ciones validas para el mismo conjunto de tablas, pero que sean las dos válidas no quiere decir que sea lo que realmente se quiso representar (o sea, no es lo mismo decir que cuatro entidades se relacionan mediante una agregación entre tres de las entidades, y una relación simple con la cuarta entidad, que decir que se relacionan mediante una relación cuaternaria).

Existen dos posibilidades para solucionar este problema. Una es si los atributos que componen a la clave foránea que representa a la entidad cuyos atributos no componen a la clave primaria de la tabla admiten valores nulos, pues entonces estamos en el primer caso (es decir, en el caso de la agregación con una relación simple). Esto es así porque si fuese una relación entre todas las entidades ninguna clave foránea puede aceptar valores nulos.

La segunda opción es estudiar si existe una relación 1–1 cruzada entre la clave foránea que no compone la clave primaria y la entidad que esta relaciona. En el caso de existir una relación 1–1 cruzada entonces estamos completamente seguros que nos encontramos frente a el primer caso.

Si no se puede llegar a probar ninguna de las dos opciones antes planteadas, entonces no podemos deducir nada a partir de los datos de la estructura de la base de datos.

Relación n–aria con todas sus cardinalidades 1

Para determinar si una relación pertenece a este tipo debemos estudiar sus claves candidatas (es decir, sus claves únicas). En este caso sabemos que toda clave foránea que pertenezca a una entidad que esta tabla relaciona se debe encontrar ya sea en la clave primaria o en alguna de sus claves únicas.

A continuación planteamos un ejemplo de este tipo de relación por medio de una relación ternaria:

Matrículas Vehículos
Número_Matrícula (PK) Número_Matrícula (PK)
 
Departamentos Matrículas_Vehículos_Departamentos
Número_Departamento (PK) Número_Matrícula (PKFK)
Número_Vehículo (PKFK)
Número_Departamento (FK)

En este caso existirán dos claves únicas además de la clave primaria. Dichas claves únicas son (Número_Matrícula, Número_Departamento) y (Número_Vehículo, Número_Departamento).

Entonces en este caso deducimos que la relación es 1-1-1 debido a que al haber una clave foránea que no es primaria, entonces sabemos que la cardinalidad de la entidad a la cual hace referencia dicha clave foránea es 1. Ahora listamos todas las claves únicas con los atributos que la componen. Para cada caso aquel atributo que no se encuentre en una clave única y que nosotros sepamos que hace referencia a una entidad que relaciona la tabla, entonces sabemos con certeza que tiene cardinalidad 1, es decir, si Número_Matrícula-Número_Departamento componen una clave única sabemos que Número_Vehículo tiene cardinalidad 1.

Ahora pasaremos a justificar lo anterior con un ejemplo, ingresando algunas tuplas a las tablas de la relación antes citada.

Matrículas_Vehículos_Departamentos Válido
Núm_Mat Núm_Veh Núm_Dep
SAK 445 4670 10
SAK 445 890 10 No
SSD 320 430 11
DFF 440 4670 10 No

Debido a que Número_Matrícula, Número_Vehículo son clave primaria de la tabla, entonces deducimos que la entidad Departamentos tiene cardinalidad 1.

Ahora, a partir del ejemplo que mostramos ingresando tuplas, deducimos que un valor de Número_Vehículo y Número_Departamento estos sólo pueden aparecer juntos en una misma tupla una sola vez en toda la tabla. Por ende estos dos atributos forman una clave única, deduciendo entonces que la entidad Matrículas tiene cardinalidad 1. De la misma forma ocurre con la entidad Vehículos.

Por lo tanto la representación conceptual de este conjunto de tablas es la siguiente:

Relación n–aria con sus cardinalidades mezcladas

Con cardinalidades mezcladas quiero decir que la cardinalidad de la relación no es ni todas uno ni todas enes, sino que la cantidad de cardinalidades unos y enes son variables.

Para resolver este tipo de relación, nuevamente haremos uso de las claves candidatas (claves únicas). El análisis lo haré basándome en un ejemplo.

Personas Personas_Garantes
Número_Persona (PK) Número_Persona_Garante (PK)
 
Conformes Conformes_Personas
Número_Conforme (PK) Número_Persona (PKFK)
Número_Conforme (PKFK)
Número_Persona_Garante (FK)

Como podemos observar en los esquemas que describimos anteriormente, la tabla que representa la relación tiene la siguiente clave primaria compuesta: Número_Persona, Número_Conforme; por lo cual deducimos directamente que la cardinalidad de la entidad Personas_Garantes es 1.

Luego tras analizar las claves únicas que posee la tabla deducimos que posee una clave única compuesta por los siguientes atributos: Número_Conforme, Número_Persona_Garante, por lo cual deducimos que la entidad Personas también posee cardinalidad 1. Finalmente al no poseer más claves únicas llegamos a la conclusión de que la cardinalidad de esta relación es 1-1-N.

A continuación presentamos un ejemplo por medio del cual podemos deducir la lógica antes nombrada sobre la utilización de las claves únicas:

ConformesPersonas Válido
Núm_Per Núm_Con Núm_Per_Gar
888 456 456
976 321 231
682 321 231 No

Debido a que Número_Persona_Garante no pertenece a la clave primaria de la relación deduzco que la cardinalidad de la entidad Personas_Garantes es 1.

A partir del ejemplo anterior deducimos que dado cierto valor de Número_Conforme y Número_Persona_Garante estos valores juntos pueden aparecer una sola vez en toda la tabla, por lo tanto deducimos que la cardinalidad de la entidad Personas es 1. Debido a que la entidad Conformes pertenece a todas las claves únicas que hay en la tabla, deduzco que su cardinalidad es N.

Por lo tanto la representación conceptual del conjunto de tablas expuestos anteriormente, es la siguiente:

Análisis de una agregación

En el análisis anterior fuimos descubriendo (en algunos casos) aquellas tablas que componían una agregación.

Aquí no trataremos un análisis de como determinar una agregación, debido a que una agregación no es más que una relación especial, ya que la agregación se utiliza para relacionar una relación con una entidad o conjunto de entidades, o con otra agregación o conjunto de agregaciones, o con ambas.

Ahora, a la hora de representar el modelo conceptual nos puede interesar identificar cuando una tabla que representa una relación relaciona a una agregación con otras estructuras. Para identificar esto nos fijamos si alguna de las entidades que relaciona es a su vez una relación, en ese caso deducimos que la relación a la cual se hace referencia es una agregación (debido a que la única forma de relacionar relaciones es por medio de agregaciones).

Aplicación de ejemplo

La aplicación que implementé la realicé en Delphi 6. Mi elección radicó en que desde mi punto de vista Delphi es una herramienta sumamente potente, fácil de aprender, y además es el lenguaje en el que poseo más experiencia. De todas formas mi idea es que tras leer el análisis se pueda realizar en cualquier lenguaje y con cualquier base de datos. En mi caso utilicé a modo de ejemplo un servidor Oracle 8i Lite.

El código fuente completo de la aplicación puede bajarse de http://www.latiumsoftware.com/descarga/iibd.zip

 
TecnoSoft Application Development - Creando soluciones para PYMEs
Copyright © 2000/2006 Ernesto De Spirito.   Todos los derechos reservados.