Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
INTRODUCCIÓN
En el desarrollo de la estructura de tablas de una base de
datos se deben tener en cuenta “muuuuuchas” cosas. Si
alguien no sabe de qué estamos hablando le recomiendo
que eche un ojo a algunos de estos → (artículos).
Sin embargo, en este documento voy a profundizar en algo que se denominan las “formas
normales”. Existen cinco formas normales, de las cuales las tres primeras son las que explicaré
en más profundidad. La cuarta y la quinta rara vez se toman en cuenta para la realización de
un diseño, dado que usualmente el no tenerlas en cuenta no afectará a la funcionalidad de
nuestra aplicación (y esto último no son palabras mías, sino de Microsoft). Estas últimas no las
explicaré aquí, pero en un penúltimo epígrafe de este artículo os daré unas páginas donde
podréis consultar todo lo referente a lo explicado y no explicado en este documento.
Probablemente (ojo, digo probablemente) esa base de datos será una base de datos simple,
sin interconexiones complejas entre sus tablas. Y, también probablemente, si esa base de
datos tuviera que crecer en cantidad y complejidad sería cuando se pondrían de manifiesto
algunos (o muchos) problemas que habrían podido evitarse fácilmente con solo aplicar las
formas normales.
Situándonos en un plano más técnico, los dos motivos principales que se suelen apuntar para
aplicar las formas normales son:
Eliminar redundancias
Para verlo más claro, ¿qué problemas podrían derivarse de lo anterior? Analicémoslo desde una
primera perspectiva: una sola tabla.
Imaginemos que tenemos una tabla con un campo donde introducimos la provincia. E
imaginemos que el usuario introduce, en algunos registros, “Andalucía”, en otros “Andalucia”,
en otros, por desliz de dedos, “Amdalucia”, y así todas las variaciones que se nos ocurran. Hay
que tener en cuenta que, para Access, “Andalucía” no es lo mismo que “Andalucia” (sin acento
gráfico), y mucho menos “Amdalucia”.
¿Qué problemas se nos derivarán de todo lo anterior? Pues básicamente que las ordenaciones,
los filtros, las agrupaciones y los sumatorios agrupados y, en general, toda la información que
requiera ese valor, nos dará resultados erróneos.
1
Visítame en http://bit.ly/NckAccess
Veámoslo desde una segunda perspectiva: dos o más
tablas. Tenemos varias tablas, y en ellas tenemos un campo
en el que escribimos, cada vez, “Chequia”, por ejemplo. Y
cuando llevamos ya una buena cantidad de registros nos
comunican que, en los informes, no puede aparecer
“Chequia”, sino que se quiere que aparezca “República
Checa”. Como podréis imaginar, eso implicaría, primero,
saber en qué tablas se está recogiendo ese dato y,
segundo, tener que cambiar todos los registros donde
aparezca “Chequia”. Y, por si fuera poco, ¿qué pasaría si
algún usuario ha estado escribiendo “Chekia”?
Por supuesto me he estado centrando en un solo valor, pero cuando hablamos de redundancias
hablamos también de grupos de información. Es decir, no tendría demasiado sentido, en este
contexto, guardar los datos personales de un trabajador (NIF, domicilio, estado civil, fecha de
nacimiento…) en una tabla y, a su vez, guardar esos mismos datos en otra u otras tablas. Eso
sería redundante.
Y lo anterior nos liga con la idea de dependencias incoherentes. Imaginemos que tenemos
unos socios de un club de petanca. Tenemos una tabla donde, en función de la edad del socio,
le asignamos una cuota mensual. Hasta aquí perfecto. Lo que resultaría incoherente (y poco
intuitivo, además) es que esa tabla donde informemos de las cuotas la utilicemos para
almacenar también los datos personales del socio. Aunque existe una relación entre socio-
cuota socio, no resulta una dependencia coherente que los datos del socio estén en la misma
tabla donde almacenamos la información de las cuotas.
Además, con mucha probabilidad, aunque eso sí dependerá de cómo se haya estructurado,
podría darse el caso de que al querer sacar un listado de socios ese listado nos devolviera
información incompleta por no mostrarnos, por ejemplo, aquellos socios a los cuales aún no se
les ha asignado una cuota.
Vistos esos “problemillas” veamos cómo la aplicación de las normas formales pueden solventar
la mayoría de los mismos.
Imaginemos que tenemos un club de actividades para la tercera edad. Y tenemos que recoger
las actividades a las que se apuntan los ancianitos. Una primera aproximación podría ser la
siguiente, donde el número de socio es clave principal y, por tanto, no admite duplicados:
2
Visítame en http://bit.ly/NckAccess
Vamos a dar de alta un nuevo usuario. Y, al hacerlo, vemos
que se nos presenta uno de los problemas que
comentábamos en el epígrafe anterior: la socia 6, Sonia
Lenta, quiere ir a JiuJitsu. Eso nos obliga, en ese nuevo
registro, a tener que volver que escribir tres datos
“repetidos”: el nombre de la actividad, el nombre del
monitor y la hora de inicio de la actividad.
Ahora el socio número 1 está apuntado a dos actividades. Y eso supone añadir campos cuyos
valores se duplican (hay que volver a escribir los valores de tres campos que ya están
escritos).
Lo que vemos en esta tabla, en realidad, es que se están recogiendo dos “grupos” de
información en la misma tabla: los datos del socio (nombre y fecha de nacimiento) y los datos
de las actividades (nombre de la actividad, nombre del monitor y hora de inicio de la
actividad). Y precisamente ese segundo grupo, que está en función del socio, es el que debe
repetirse según el número de actividades a las que se apunte el socio.
Dado que la primera forma normal nos dice que hay que eliminar los grupos repetidos de las
tablas individuales debemos separar esos grupos en dos tablas: una para recoger los datos de
los socios y otro para recoger los datos de las actividades. Veamos…
Con ello hemos conseguido cumplir las dos primeras premisas de la primera forma normal:
hemos eliminado los grupos repetidos y hemos creado tablas independientes para cada uno de
los grupos de datos.
Si la respuesta es que sí, la pregunta que os lanzo es: ¿qué pasaría si cada actividad pudiera
tener más de un monitor? ¿Qué pasaría si se nos pidiera que también se almacenara la fecha
de nacimiento de cada monitor?
En realidad, en la tabla de la derecha volvemos a tener dos grupos de datos: los datos de la
actividad (nombre y hora de inicio), por un lado, y los datos de los monitores (nombre y fecha
3
Visítame en http://bit.ly/NckAccess
de nacimiento). Apliquemos pues de nuevo la primera forma normal y obtengamos…
El tercer postulado de la forma nos indica que hay que identificar cada conjunto de datos con
una clave principal. Eso ya lo tenemos hecho para los socios, donde el número de socio es la
clave principal. Así que vamos a hacerlo para las dos tablas que aún no tienen clave principal.
Y con esto podemos decir que ya tenemos nuestra base en la “primera forma normal”.
En realidad el primero de los postulados ya lo hemos cumplido con las acciones que hemos
realizado en el epígrafe anterior. Si os fijáis, hemos aplicado ese postulado en dos ocasiones:
1.- Cuando hemos dicho que un socio puede apuntarse a distintas actividades, lo que implicaba
la repetición de las actividades (la actividad se aplicaba a varios registros de socios).
2.- Cuando hemos dicho una actividad puede ser desarrollada por varios monitores, lo que
implicaba la repetición de monitores (los monitores se aplicaban a varios de registros de
actividad).
Así pues, y en nuestro ejemplo, solo nos queda cumplir con el segundo postulado de la forma,
que es crear una relación entre las distintas tablas independientes a través de una clave
externa.
Y para ello vamos a realizar el proceso en dos pasos pivotando sobre los socios. El primer paso
es crearnos una “lista” de socios con sus actividades. Y para ello necesitaremos dos elementos:
¿qué socio es y a qué actividad se ha apuntado?
4
Visítame en http://bit.ly/NckAccess
Y sus relaciones, tal como indica el postulado, será relacionar la clave primaria de los socios
con la clave foránea (externa) de nuestra tabla de relaciones, al mismo tiempo que se
relaciona la clave primaria de las actividades con la clave foránea de nuestra tabla de
relaciones.
Vamos a por la segunda fase: ¿qué monitor desarrolla la actividad a la que se ha apuntado el
socio? Pues lo que haremos será añadir esa información a nuestra tabla de relaciones, de la
siguiente manera:
Fijaos que, en el último registro, con la actividad “Costura”, podemos elegir a cualquiera de los
monitores que tenemos en plantilla. Quizás, en lugar de Ana Agujas, el señor Lu Chen también
podría ser monitor de costura…
5
Visítame en http://bit.ly/NckAccess
Llegados aquí podemos decir que nuestra base está en “segunda forma normal”.
Y empezaré diciendo que la aplicación de esta norma, aunque deseable a nivel teórico, no
siempre es recomendable a nivel práctico. Podría ser que, por la estructura de nuestras tablas
y de nuestros datos no nos resultara práctico aplicar esta norma, así que… simplemente, no la
aplicamos.
Lo anterior para transmitiros que, en ocasiones, la teoría se desliga de la práctica, y que eso
no debe sorprendernos. Eso lo veremos en detalle en un epígrafe posterior.
Retomemos nuestra tabla de socios e imaginemos que queremos almacenar en qué provincia
nacieron.
Una primera aproximación sería remozar nuestra tabla con dicha información, así:
Si nos ponemos en plan purista, si bien es cierto que hay una dependencia entre la clave
principal y la provincia de nacimiento, en realidad la provincia de nacimiento es un elemento
independiente que existe sin necesidad de que exista el valor de la clave principal. Dicho de
otra manera un poco más burda, la provincia “Sevilla” existe, aunque en la tabla no tengamos
ningún socio que haya nacido ahí.
En aplicación de la tercera forma normal deberíamos separar esas provincias en una tabla
independiente y crear una relación entre ellas, de la siguiente manera (y siendo estricto en la
interpretación del modelo):
6
Visítame en http://bit.ly/NckAccess
Tened en cuenta, como añadido, que si en algún momento
nos solicitaran, por ejemplo, las provincias de nacimiento
de los monitores no tendríamos más que, en la tabla donde
recogemos los datos, añadir un campo adicional de relación
con nuestra tabla de provincias (e, insisto en la idea, eso
nos permitiría alcanzar el objetivo de “escribir lo menos
posible”, puesto que no tendríamos que volver a dar de alta
todas las provincias).
RESUMIENDO…
Si os habéis fijado y habéis ido siguiendo el ejemplo en realidad nos hemos situado en un
punto de partida “donde
lo tenemos todo” (véase
“Ilustración 1”) y todos
los datos deben ser
introducidos a mano cada
vez que damos de alta un
registro y, por aplicación
de las formas normales, Ilustración 1
hemos ido, en una
primera fase, descomponiendo atómicamente cada uno de los grupos o “bloques” de
información no directamente relacionados entre sí en diferentes tablas (asignándoles una clave
principal en cumplimiento de la forma normal primera) tal y como muestra la “Ilustración 2”
(información solo de socios), “Ilustración 3” (información solo de provincias), “Ilustración 4”
(información solo de actividades) e “Ilustración 5” (información solo de monitores).
Ilustración 2 Ilustración 3
Ilustración 4 Ilustración 5
En una segunda fase hemos dicho: “ahora que tenemos los diferentes bloques de información
hay que ver cómo se relacionan unos con otros”, lo que nos ha llevado a crear, por un lado,
7
Visítame en http://bit.ly/NckAccess
una tabla intermedia que nos “une” los bloques principales de información (“Ilustración 6”), y
por otro el diseño de las relaciones a nivel gráfico (“Ilustración 7”).
Ilustración 6
Ilustración 7
DESNORMALIZACIÓN
Bueno… Ya tenemos nuestra base de datos totalmente adaptada, al menos, a las tres primeras
formas normales; ergo, nuestra base está perfectamente normalizada cumpliendo la 1FN, la
2FN y la 3FN.
Y, ahora es cuando rompemos los esquemas y decimos que “podría ser recomendable, en
nuestra base de datos, romper alguno de los postulados de las formas normales que hemos
visto y, en consecuencia, que nuestra base de datos no estuviera perfectamente normalizada”.
8
Visítame en http://bit.ly/NckAccess
Ya hemos visto que si no tenemos nuestra base de datos
normalizada y hemos ido dando de alta en cada registro de
cada una de las tablas anteriores la provincia de
nacimiento, si nos damos cuenta de que hemos escrito
“Lérida” y queremos que, a partir de ahora, nos aparezca
“Lleida” tendríamos que recorrer tabla a tabla todos los
registros, ver en cuáles se ha escrito “Lérida” y modificarlo
por “Lleida”.
Si tenemos nuestra base de datos normalizada, el mantenimiento de este cambio es tan simple
como irse a la tabla provincias, buscar el registro donde pone “Lérida” y cambiarlo por “Lleida”.
Y de esta manera estamos seguros de que todas las tablas donde el campo de la provincia de
nacimiento está ligado con nuestra tabla provincias contienen ya la información correcta.
Mantenimiento fácil, sencillo y efectivo.
Pues básicamente podemos definirla como el proceso de agregación de datos redundantes para
una optimización de respuesta de la base de datos.
Sin embargo no debemos confundir conceptos: una cosa es una base de datos desnormalizada
y otra cosa es una base de datos sin normalizar. No podemos desnormalizar si antes no hemos
normalizado la base de datos, o, dicho de otra manera, la secuencia del proceso es: a)
Normalizar la base de datos; b) Desnormalizar la base de datos.
Lo anterior, esto es, desnormalizar una base de datos, requiere que tengamos en cuenta los
siguientes elementos:
La capacidad de almacenamiento
La necesidad de acceder a los datos rápidamente
El control que se necesite para evitar inconsistencias
La necesidad de archivo de datos históricos
CAPACIDAD DE ALMACENAMIENTO
Aunque hoy en día la capacidad de almacenamiento de los PC’s ha convertido en algo trivial
(en términos relativos, claro) el preocuparse por “si tengo espacio disponible”, en el caso
9
Visítame en http://bit.ly/NckAccess
concreto de Access no es algo tan trivial, dado que ya sabemos que el tamaño de un fichero de
Access no puede superar los 2GB.
En consecuencia, tener esos resultados almacenados “de antemano” puede suplir esa merma
en el rendimiento de la aplicación.
Pongamos un ejemplo “tonto” (o no): imaginemos que tenemos una tabla con la información
de nuestros clientes, de nuestros proveedores (entendidos como terceros que suministran
materias primas), de nuestros acreedores (entendidos como terceros que no suministran
materias primas), de nuestros partners, de nuestros…
Imaginemos que cada cierto tiempo queremos realizar un envío de e-mail a todos esos,
llamémosles genéricamente, “colaboradores”. Una manera de hacerlo sería tener una consulta
de unión que nos recogiera los datos que necesitamos de cada uno de ellos. Imaginemos que,
por el volumen de registros, obtener los datos nos tardará, en términos de usuario de la
aplicación, “una eternidad” ;-)
Una opción a lo anterior sería crear una tabla temporal donde se recogieran los resultados de
esa consulta y que, cuando el usuario quisiera preparar ese mail, accediera directamente a esa
tabla temporal.
Lógicamente, lo que no tendría sentido sería crear tablas temporales “de todo”. Ahí hay un
trabajo de análisis para poder determinar qué es lo que realmente se necesita.
¿Qué podría provocarnos una incoherencia? Pues algo tan simple, siguiendo el ejemplo anterior
de nuestra lista de e-mail, que un cliente nos informara de que ha cambiado el e-mail de
contacto. Así, tendríamos en la tabla de clientes, que el cliente número 15.255 tiene un correo
electrónico periquito@avesmundi.net, mientras que ese mismo cliente, en nuestra tabla
temporal, tiene el correo electrónico aveperico@avesterra.net. Es decir, tenemos un dato
incongruente.
Supongamos que se requiere con asiduidad un informe sobre las ventas del año en curso, y
que, por la complejidad de los datos, sus diferentes procedencias y su gran volumen, nos
hemos creado una tabla temporal para tener ya los datos “a mano”. Así, nos encontramos con
10
Visítame en http://bit.ly/NckAccess
dos incongruencias posibles: una, que los datos no se actualizan en la tabla temporal con las
nuevas ventas y, dos, que si hay algún cambio en los datos existentes, esos datos “reales”
existentes no se corresponden con los datos de nuestra tabla temporal.
Nuestro programa nos permite emitir facturas, así que en las líneas de detalle de la factura,
seleccionamos el artículo y su cantidad, y una hermosa consulta (o un campo calculado) se
dedica a calcular el importe total buscando el precio del artículo y multiplicando por la cantidad
vendida.
Vamos sacando nuestras facturas de enero a junio, sin ningún problema. Pero en julio el jefe
nos dice que tenemos que aumentar el precio de todos nuestros artículos en un 10%. También,
sin problema, actualizamos todos los precios con ese incremento del 10% y seguimos
emitiendo facturas sin problemas aparentes.
¿Cuál será el problema? Pues el problema será que, si sacamos un informe de ventas en junio
y hasta el 30 de junio, veremos que hemos tenido unas ventas de x euros, pero si sacamos
ese mismo informe en julio veremos que las ventas de enero a junio no han sido x euros, sino
x+0,1x (es decir, un 10% más).
En este caso no podemos permitirnos el lujo de que una actualización de datos afecte a la
información relacionada en otras tablas, puesto que estaríamos perdiendo la información
histórica (y, evidentemente, los resultados de nuestro informe sacado en julio no serían
reales).
¿Solución? Crear una redundancia y almacenar, otra vez, el precio del artículo en la tabla de
las líneas de factura. En este caso se ve claramente la necesidad de desnormalizar para
conservar una información veraz de lo que ha sucedido en la realidad.
WEBGRAFÍA
Aunque si introducís en un buscador las palabras clave “normalización base de datos” o
“desnormalización base de datos” vais a encontrar multitud de resultados, os indico a
continuación los que me han servido de base para poder redactar este artículo:
11
Visítame en http://bit.ly/NckAccess
Normalización
Cuarta y quinta formas normales (para quien desee profundizar en las mismas)
Desnormalización
La información que he visto por ahí resulta, en general, un tanto genérica y “confusa” en
cuanto se piensa en una aplicación a una base de datos Access (ojo, en los enlaces que he
estado revisando yo). Así que me quedo, como compendio de lo que es “desnormalización”, en
lo que se describe y explica en el siguiente enlace:
¡suerte!
12
Visítame en http://bit.ly/NckAccess