Dependencia funcional transitiva

Definición: Supongamos que tenemos una relación con tres conjuntos de atributos: X, Y y Z, y las siguientes dependencias X -> Y, Y -> Z, Y -> |X. Es decir X determina Y e Y determina Z, pero Y no determina X. En ese caso, decimos que Z tiene dependencia transitiva con respecto a X, a través de Y.

Intentaremos aclarar este concepto tan teórico con un ejemplo. Si tenemos esta relación:

Ciudades(ciudad, población, superficie, renta, país, continente)

Los atributos como población, superficie o renta tienen dependencia funcional de ciudad, así que de momento no nos preocupan.

En esta relación podemos encontrar también las siguientes dependencias:

ciudad -> país, país -> continente. Además, país -> |ciudad. Es decir, cada ciudad pertenece a un país y cada país a un continente, pero en cada país puede haber muchas ciudades. En este caso continente tiene una dependencia funcional transitiva con respecto a ciudad, a través de país. Es decir, cada ciudad está en un país, pero también en un continente. (¡Ojo! las dependencias transitivas no son siempre tan evidentes :-).

Tercera forma normal 3FN

La tercera forma normal consiste en eliminar las dependencias transitivas.

Definición: Una base de datos está en 3FN si está en 2FN y además todas las columnas que no sean claves dependen de la clave completa de forma no transitiva.

Pero esto es una definición demasiado teórica. En la práctica significa que se debe eliminar cualquier relación que permita llegar a un mismo dato de dos o más formas diferentes.

Tomemos el ejemplo que usamos para ilustrar las dependencias funcionales transitivas. Tenemos una tabla donde se almacenen datos relativos a ciudades, y una de las columnas sea el país y otra el continente al que pertenecen. Por ejemplo:

Ciudades(ID_ciudad(PK), Nombre, población, superficie, renta, país, continente)

Un conjunto de datos podría ser el siguiente:

Ciudades
ID_ciudad  Nombre    población  superficie  renta  país      continente
1          Paris      6000000   15          1800   Francia   Europa
2          Lion       3500000   9           1600   Francia   Europa
3          Berlin     7500000   16          1900   Alemania  Europa
4          Pekin     19000000   36           550   China     Asia
5          Bonn       6000000   12          1900   Alemania  Europa

Podemos ver que para cada aparición de un determinado país, el continente siempre es el mismo. Es decir, existe una redundancia de datos, y por lo tanto, un peligro de integridad.

Existe una relación entre país y continente, y ninguna de ellas es clave candidata. Por lo tanto, si queremos que esta table sea 3FN debemos separar esa columna:

Ciudades(ID_ciudad(PK), Nombre, población, superficie, renta, nombre_pais)
Paises(nombre_pais(PK), nombre_continente)
Ciudades
ID_ciudad  Nombre    población  superficie  renta  país
1          Paris      6000000   15          1800   Francia
2          Lion       3500000   9           1600   Francia
3          Berlin     7500000   16          1900   Alemania
4          Pekin     19000000   36           550   China
5          Bonn       6000000   12          1900   Alemania
Paises
país      continente
Francia   Europa
Alemania  Europa
China     Asia

Esta separación tendría más sentido si la tabla de paises contuviese más información, tal como está no tiene mucho sentido separar estas tablas, aunque efectivamente, se evita redundancia.

Forma Normal de Boycce y Codd (FNBC)

Definición: Una relación está en FNBC si cualquier atributo sólo facilita información sobre claves candidatas, y no sobre atributos que no formen parte de ninguna clave candidata.

Esto significa que no deben existir interrelaciones entre atributos fuera de las claves candidatas.

Para ilustrar esta forma normal volvamos a uno de nuestros ejemplos anteriores, el de las ocupaciones de habitaciones de un hotel.

Ocupación(No_cliente, Nombre_cliente, No_habitación, fecha_entrada)
Habitación(No_habitación(PK), precio_noche, tipo_habitación)

En la primera relación los atributos No_cliente y Nombre_cliente sólo proporcionan información entre ellos mutuamente, pero ninguno de ellos es una clave candidata.

Intuitivamente ya habremos visto que esta estructura puede producir redundancia, sobre todo en el caso de clientes habituales, donde se repetirá la misma información cada vez que el mismo cliente se aloje en el hotel.

La solución, como siempre, es simple, y consiste en separar esta relación en dos diferentes:

Ocupación(No_cliente, No_habitación, fecha_entrada)
Cliente(No_cliente(PK), Nombre_cliente)
Habitación(No_habitación(PK), precio_noche, tipo_habitación)

Atributos multivaluados

Definición: se dice que un atributo es multivaluado cuando para una misma entidad puede tomar varios valores diferentes, con independencia de los valores que puedan tomar el resto de los atributos.

Se representa como X ->-> Y, y se lee como X multidetermina Y.

Un ejemplo claro es una relación donde almacenemos contactos y números de teléfono:

Agenda(nombre, fecha_nacimiento, estado_civil, teléfono)

Para cada nombre de la agenda tendremos, en general, varios números de teléfono, es decir, que nombre multidetermina teléfono: nombre ->-> teléfono.

Además, nombre determina funcionalmente otros atributos, como la fecha_nacimiento o estado_civil.

Por otra parte, la clave candidata no es el nombre, ya que debe ser unívoca, por lo tanto debe ser una combinación de nombre y teléfono.

En esta relación tenemos las siguientes dependencias:

  • nombre -> fecha_nacimiento
  • nombre -> estado_civil
  • nombre ->-> teléfono, o lo que es lo mismo (nombre,teléfono) -> teléfono

Es decir, la dependencia multivaluada se convierte, de hecho, en una dependencia funcional trivial.

Este tipo de atributos implica redundancia ya que el resto de los atributos se repiten tantas veces como valores diferentes tenga el atributo multivaluado:

Agenda
nombre    fecha_nacimiento   estado_civil   teléfono
Mengano   15/12/1985         soltero        12322132
Fulano    13/02/1960         casado         13321232
Fulano    13/02/1960         casado         25565445
Fulano    13/02/1960         casado         36635363
Tulana    24/06/1975         soltera        45665456

Siempre podemos evitar el problema de los atributos multivaluados separandolos en relaciones distintas. En el ejemplo anterior, podemos crear una segunda relación que contenga el nombre y el teléfono:

Agenda(nombre(PK), fecha_nacimiento, estado_civil)
Teléfonos(nombre, teléfono(PK))

Para los datos anteriores, las tablas quedarían así:

Agenda
nombre    fecha_nacimiento   estado_civil
Mengano   15/12/1985         soltero
Fulano    13/02/1960         casado
Tulana    24/06/1975         soltera

Teléfonos
nombre     teléfono
Mengano    12322132
Fulano     13321232
Fulano     25565445
Fulano     36635363
Tulana     45665456