Como hemos visto en este artículo:

https://firebird21.wordpress.com/2013/08/18/consideraciones-a-tener-en-cuenta-al-disenar-una-base-de-datos/

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:

  1. No hay orden de arriba-abajo en las filas
  2. No hay orden izquierda-derecha en las columnas
  3. No hay filas duplicadas
  4. Cada campo tiene un solo valor
  5. Todos los valores de una columna tienen el mismo significado
  6. 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.

1FN1

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:

1FN2

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:

1FN3

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:

1FN4

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:

1FN5

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:

1FN7

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.

1FN6

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

El índice del blog Firebird21