Normalizar es repartir los datos en tablas de forma que cada dato se guarde una sola vez. Es el paso que va entre el modelo entidad-relación y el CREATE TABLE: decide qué tablas hacen falta y qué columnas lleva cada una.

Se hace aplicando unas reglas llamadas formas normales. Hay varias, pero en la práctica, con las tres primeras basta para la mayoría de las bases de datos.

El problema: una tabla que lo guarda todo

Imagina que la tienda guarda sus pedidos en una sola hoja, tal y como llegan:

idPedido cliente direccionCliente productos descripciones precios
1 Ana Fernandez Av. de Santiago 11 Xiaomi Mi 11 Smartphone 286,95
2 María Lopez C/ Alcalá 138 Play Station 5, Xbox series X Consola Sony, Consola Xbox 549,95, 499,99
3 Luis Sanchez C/ de la luz 21 Echo DOT 3, Echo DOT 4 Altavoz Alexa, Altavoz Alexa 39,99, 59,99

Funciona mientras es pequeña, pero tiene tres problemas, llamados anomalías:

  • De actualización. Si María cambia de dirección hay que corregirla en todos sus pedidos. Si se olvida uno, la base de datos tiene dos direcciones para la misma persona.
  • De inserción. No se puede dar de alta un cliente que todavía no ha comprado nada, porque cada fila es un pedido.
  • De borrado. Si se borra el único pedido de Ana, se pierde también todo lo que sabíamos de Ana.

Además, con varios productos en una celda no hay forma sencilla de responder a “¿cuántas Xbox hemos vendido?”.

Primera forma normal (1FN): un valor por celda

Una tabla está en 1FN si:

  • Cada celda contiene un solo valor (nada de listas separadas por comas).
  • No hay grupos de columnas repetidas (producto1, producto2, producto3…).
  • Cada fila se puede identificar con una clave.

Separamos los productos en filas. La clave pasa a ser la combinación de pedido y producto:

idPedido producto cliente direccionCliente descripcion precio
1 Xiaomi Mi 11 Ana Fernandez Av. de Santiago 11 Smartphone 286,95
2 Play Station 5 María Lopez C/ Alcalá 138 Consola Sony 549,95
2 Xbox series X María Lopez C/ Alcalá 138 Consola Xbox 499,99
3 Echo DOT 3 Luis Sanchez C/ de la luz 21 Altavoz Alexa 39,99
3 Echo DOT 4 Luis Sanchez C/ de la luz 21 Altavoz Alexa 59,99

Ya se puede contar y sumar por producto, pero María y su dirección aparecen repetidos.

Segunda forma normal (2FN): todo depende de la clave completa

Una tabla está en 2FN si está en 1FN y cada columna depende de toda la clave, no solo de una parte. Solo afecta a tablas con claves de varias columnas.

Nuestra clave es (idPedido, producto). Pero:

  • cliente y direccionCliente dependen solo de idPedido.
  • descripcion y precio dependen solo de producto.

Cada grupo va a su propia tabla, y la tabla original se queda solo con lo que depende de las dos columnas juntas (en una tienda real, la cantidad de cada producto en cada pedido):

Pedidos

idPedido cliente direccionCliente
1 Ana Fernandez Av. de Santiago 11
2 María Lopez C/ Alcalá 138
3 Luis Sanchez C/ de la luz 21

Productos

producto descripcion precio
Xiaomi Mi 11 Smartphone 286,95
Play Station 5 Consola Sony 549,95
Xbox series X Consola Xbox 499,99
Echo DOT 3 Altavoz Alexa 39,99
Echo DOT 4 Altavoz Alexa 59,99

LineasPedido

idPedido producto cantidad
1 Xiaomi Mi 11 15
2 Play Station 5 4
2 Xbox series X 2
3 Echo DOT 3 50
3 Echo DOT 4 50

Ahora el precio de cada producto está en un solo sitio.

Tercera forma normal (3FN): nada depende de otra columna que no sea la clave

Una tabla está en 3FN si está en 2FN y ninguna columna depende de otra columna que no sea la clave (lo que se llama una dependencia transitiva).

En Pedidos, la dirección no depende del pedido sino del cliente: si María hace diez pedidos, su dirección se repite diez veces. La solución es la misma de antes: sacar el cliente a su propia tabla y dejar en Pedidos solo una referencia a él.

Clientes

idCliente nombre direccion
1 Ana Fernandez Av. de Santiago 11
2 María Lopez C/ Alcalá 138
3 Luis Sanchez C/ de la luz 21

Pedidos

idPedido idCliente
1 1
2 2
3 3

idCliente en Pedidos es una Foreign Key: el vínculo con la tabla Clientes. Las tres anomalías han desaparecido. La dirección se cambia en un solo sitio, se puede dar de alta un cliente sin pedidos y borrar un pedido no borra al cliente.

La regla para recordarlo

Una forma clásica de resumir las tres formas normales: cada columna debe depender de la clave, de toda la clave y de nada más que la clave.

  • “De la clave”: 1FN, cada fila se identifica por una clave y cada celda tiene un valor.
  • “De toda la clave”: 2FN.
  • “Y de nada más que la clave”: 3FN.

¿Hay que normalizar siempre?

Para las bases de datos de una aplicación, donde se escribe constantemente (pedidos, usuarios, facturas), sí: normalizar hasta 3FN evita incoherencias y es el punto de partida estándar.

Hay casos en los que se desnormaliza a propósito, como los almacenes de datos y las tablas de informes, donde casi todo son lecturas y repetir datos ahorra muchos JOIN. Pero eso es una decisión que se toma sobre un diseño normalizado, no una excusa para no hacerlo.

Las tablas Clientes y Pedidos del curso están casi normalizadas. La excepción es totalPrecio, que se calcula a partir de otras dos columnas. Es una columna calculada que SQL Server mantiene sola, así que no puede quedar desactualizada. Además, cada pedido tiene un único producto, por eso no hace falta una tabla de líneas.

Practica

  1. Una tabla Alumnos (idAlumno, nombre, asignaturas) guarda en asignaturas valores como 'Matemáticas, Física'. ¿Qué forma normal incumple y cómo la arreglarías?
  2. En una tabla Matriculas (idAlumno, idAsignatura, nombreAsignatura, nota) con clave (idAlumno, idAsignatura), ¿qué columna incumple la 2FN?
  3. En Empleados (idEmpleado, nombre, idDepartamento, nombreDepartamento), ¿qué columna incumple la 3FN?