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:
clienteydireccionClientedependen solo deidPedido.descripcionypreciodependen solo deproducto.
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.
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
- Una tabla
Alumnos (idAlumno, nombre, asignaturas)guarda enasignaturasvalores como'Matemáticas, Física'. ¿Qué forma normal incumple y cómo la arreglarías? - En una tabla
Matriculas (idAlumno, idAsignatura, nombreAsignatura, nota)con clave(idAlumno, idAsignatura), ¿qué columna incumple la 2FN? - En
Empleados (idEmpleado, nombre, idDepartamento, nombreDepartamento), ¿qué columna incumple la 3FN?