Como hemos visto en este artículo:
para que una tabla esté bien diseñada debe cumplir con las 6 formas normales. Es un estándar que todos los buenos diseñadores de bases de datos relacionales saben que deben cumplir. Una tabla que no cumpla con las formas normales podría funcionar, de hecho hay millones de tablas en millones de aplicaciones que no las cumplen y están allí usándose diariamente, pero la verdadera eficiencia solamente puede conseguirse si se cumplen las formas normales.
Para escribir menos es usual abreviar los nombres: 1FN significa Primera Forma Normal, 2FN significa Segunda Forma Normal y así sucesivamente.
1FN – Primera Forma Normal
Sirve para asegurar que no hay valores repetidos en la tabla
Una tabla está en 1FN si:
- No hay orden de arriba-abajo en las filas
- No hay orden izquierda-derecha en las columnas
- No hay filas duplicadas
- Cada campo tiene un solo valor
- Todos los valores de una columna tienen el mismo significado
- Los campos que no son clave y que pueden identificarse con una clave, deben identificarse por esa clave
La condición 1 significa que no importa en que orden se guardan las filas. O sea que si escribimos:
INSERT INTO CLIENTES (CLI_IDENTI, CLI_NOMBRE) VALUES (1, ‘Juan Pérez’)
INSERT INTO CLIENTES (CLI_IDENTI, CLI_NOMBRE) VALUES (2, ‘María Benítez’)
o si escribimos:
INSERT INTO CLIENTES (CLI_IDENTI, CLI_NOMBRE) VALUES (2, ‘María Benítez’)
INSERT INTO CLIENTES (CLI_IDENTI, CLI_NOMBRE) VALUES (1, ‘Juan Pérez’)
al consultar los datos debe ser lo mismo. Ninguna de esas formas debe ser mejor que la otra.
La condición 2 significa que no debe importar el orden en el cual se guardan las columnas para poder recuperar correctamente esas columnas. O sea que si escribimos:
INSERT INTO CLIENTES (CLI_IDENTI, CLI_NOMBRE) VALUES (1, ‘Juan Pérez’)
o si escribimos:
INSERT INTO CLIENTES (CLI_NOMBRE, CLI_IDENTI) VALUES (‘Juan Pérez’, 1)
debe ser lo mismo, en ambos casos deberíamos poder consultar correctamente a esa tabla, el orden de grabación de las columnas debe ser intrascendente.
La condición 3 requiere que la tabla tenga una Clave Primaria (Primary Key, en inglés). Si no tuviera una Primary Key entonces podría ocurrir que dos filas fueran idénticas.
Por ejemplo, si en una tabla guardamos el Código del producto vendido, la cantidad vendida y el precio de venta podría ocurrir fácilmente que dos o más veces vendamos el mismo producto, la misma cantidad y por supuesto con el mismo precio. (Varios clientes compraron 1 litro de leche, de la misma marca; por lo tanto coinciden el código, la cantidad, y el precio)
Esta condición también implica que la Primary Key no debe tener valores nulos ya que si pudiera tenerlos entonces podrían existir filas duplicadas.
La condición 4 es la que la mayoría de la gente tiene en mente cuando se habla de la 1FN. Significa que en una columna se deben tener valores atómicos, únicos.
Este es un ejemplo de una fila donde no se cumple con la condición 4 de la 1FN.
Captura 1. Si haces clic en la imagen la verás más grande
¿Por qué no se cumple con la condición 4 de la 1FN? Porque en la columna CLI_TELEFO se están guardando dos números telefónicos. Y para que cumpla en una columna se debe guardar un valor único.
Un diseñador inexperto podría pensar en solucionar ese problema de esta manera:
Captura 2. Si haces clic en la imagen la verás más grande
O sea agregando una columna para guardar en ella el segundo teléfono. ¿Y si hay clientes que tienen 3, 4, 5, teléfonos? ¿Una columna para cada teléfono? No es lo correcto
La forma correcta de solucionar ese problema es con una tabla adicional (llamada por ejemplo: CLIENTES_TEL) que tenga la siguiente estructura:
Captura 3. Si haces clic en la imagen la verás más grande
Y en la cual podríamos agregar todos los números de teléfono que quisiéramos de cada cliente:
Captura 4. Si haces clic en la imagen la verás más grande
Entonces cada cliente podría tener 1 teléfono, 2 teléfonos, 14 teléfonos, lo que sea, nunca tendríamos problema porque todos esos teléfonos se guardan en nuestra tabla CLIENTES_TEL.
La condición 5 implica que cuando miras a una columna siempre debes saber el significado de lo que estás mirando. No puedes guardar en la misma columna a veces un e-mail, a veces un teléfono, a veces una fecha, etc.
En la tabla de CLIENTES que usamos para estos ejemplos la columna CLI_NOMBRE no cumple con la condición 5 de la 1FN:
¿Por qué la columna CLI_NOMBRE no cumple con la condición 5 de la 1FN?
Porque en ella estamos guardando dos cosas distintas: el nombre del cliente y el apellido del cliente.
Una estructura mejor sería la siguiente:
Captura 5. Si haces clic en la imagen la verás más grande
Como puedes ver ahora tenemos una columna para los Nombres y otra columna para los Apellidos. Sin duda que hemos mejorado pero … este cliente tiene 2 apellidos y hay muchos clientes que tienen 2 nombres e inclusive 3 nombres. ¿Debemos seguir refinando nuestra estructura para tener una columna para cada nombre y una columna para cada apellido? Si vas a seguir al pie de la letra la condición 5 de la 1FN entonces sí, pero para estos casos es perfectamente admisible terminar aquí, salvo que por algún motivo necesites consultar por el segundo nombre o por el segundo apellido, entonces sí que deberías tener columnas adicionales para ellos.
La condición 6 establece que siempre que una fila tenga un identificador debe usarse ese identificador y no otras columnas de esa fila.
Por ejemplo, si nuestra tabla CLIENTES_TEL tuviera esta estructura, estaría muy mal:
Captura 6. Si haces clic en la imagen la verás más grande
En la Captura 6 vemos un ejemplo de lo que no debe hacerse, eso está terriblemente mal. ¿Por qué? porque cada cliente puede ser identificado mediante una columna llamada CLI_IDENTI que es su Primary Key, y siempre debemos usar esa Primary Key para identificarlo, no su nombre, ni su apellido, ni su e-mail, ni su número de documento de identidad ni alguna otra columna. Debemos usar la Primary Key y nada más que la Primary Key, siempre, en el 100% de los casos.
Cumpliendo con la 1FN
No debes preocuparte por la condición 1 ni por la condición 2 de la 1FN ya que el propio Firebird se encarga de eso, nunca tendrás problemas allí. La condición 3 sí ya te compete, todas tus tablas deben tener una Primary Key y lo mejor es usar para ellas una columna autoincremental, de esa manera te olvidas de asignarle valores a esa columna ya que nuevamente será el Firebird quien se encargará de esa tarea.
Captura 7. Si haces clic en la imagen la verás más grande
La condición 4 es de tu absoluta incumbencia, el Firebird no puede ayudarte con eso, él no puede saber si en una columna se está introduciendo un solo valor o varios valores (un solo teléfono o varios teléfonos, según nuestro ejemplo). Por lo tanto es tu responsabilidad como diseñador impedir que tal cosa ocurra.
La condición 5 también es total responsabilidad tuya. Tampoco el Firebird puede saber si todos los valores dentro de una columna tienen el mismo significado o si tienen significados diferentes (nombres y apellidos en una sola columna, como en nuestro ejemplo).
La condición 6 es también responsabilidad toda tuya, el Firebird no puede saber si siempre usas la Primary Key para identificar a las filas de una tabla (que es lo que debes hacer el 100% de las veces) o si a veces utilizas otras columnas (algo que nunca deberías hacer).
NOTA:
Como la 1FN fue inicialmente introducida para restringir relaciones y no tablas entonces hay discrepancias entre los autores sobre cuales condiciones debe reunir una tabla para ser considerada que cumple con la 1FN. En lo que todos están de acuerdo es que debe cumplir con la condición 4.
Conclusión:
Si todas tus tablas cumplen con la 1FN entonces no tendrás valores repetidos, ni columnas con varios significados y estarás seguro de poder identificar a cada fila de cada tabla sin equivocación posible.
Artículos relacionados:
Consideraciones a tener en cuenta al diseñar una Base de Datos
Entendiendo a las Primary Keys
Consideraciones a tener en cuenta al diseñar una Base de Datos | Firebird SQL
Ago 19, 2013 @ 15:44:50
El índice del blog Firebird21 | Firebird SQL
Ago 19, 2013 @ 15:46:19
Más ejemplos de tablas que no cumplen con la 1FN | Firebird SQL
Ago 19, 2013 @ 19:48:33
Diseño de bases de datos. 2FN | Firebird SQL
Ago 20, 2013 @ 17:01:19
Diseño de bases de datos. 3FN | Firebird SQL
Ago 20, 2013 @ 22:52:16
ManoloGS
Dic 09, 2013 @ 11:03:17
«La condición 6 establece que siempre que una fila tenga un identificador debe usarse ese identificador y no otras columnas de esa fila.»
La captura 6 no tiene creado el campo identificador del cliente .. supongamos que si lo tiene creado … ¿tiene sentido en «algun caso» mantener en l atabla de teléfonos los campos cli_nombre y cli_apellid?
Hablo de … en la cabecera de una factura tengo el «identificador» del cliente y en la tabla de clientes «forma pago», si al imprimir, al buscar o al presentar rejillas de facturas preciso «forma pago» … ¿debería crear forma pago en facturas?
No se si me explico bien, gracias….
wrov
Dic 09, 2013 @ 11:20:48
La captura 6 es un ejemplo de lo que NO DEBE HACERSE.
Los datos variables de tus clientes (los números de teléfono, por ejemplo) deberían guardarse en tablas separadas, especificando la fecha y hora en que se agregaron o modificaron. Sí, lleva más trabajo hacerlo así pero te da la seguridad de poder recuperar cuando quieras lo que ocurrió en cualquier momento.
Saludos.
Walter.