====== 02 - Normalización ======
La **normalización** comprueba que los datos están bien repartidos entre tablas: cada dato se guarda **una sola vez**. El diseño parte del diagrama de clases (tema 01); estas reglas lo **validan** y detectan los errores que la traducción no muestra.
===== 1. Una tabla mal diseñada =====
¿Qué pasa si libros y editoriales se mezclan en una única tabla? Los datos de la editorial se repiten en todas sus filas:
CREATE TABLE book (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(200) NOT NULL,
price DECIMAL(10,2) NOT NULL,
publisher_name VARCHAR(100) NOT NULL,
publisher_city VARCHAR(100) NOT NULL
);
^ Anomalía ^ Con esta tabla ^
| **Inserción** | No se puede guardar una editorial sin que tenga libros: no hay fila donde poner sus datos |
| **Actualización** | Cambiar la ciudad de una editorial obliga a actualizar **todas** sus filas; si una se queda atrás, la tabla se contradice |
| **Borrado** | Borrar el último libro de una editorial borra también sus datos |
La redundancia es la causa: el mismo dato, copiado en muchas filas, se actualiza — o se pierde — de forma incompleta. Se corrige al llegar a la **tercera forma normal**.
===== 2. Primera forma normal (1FN) =====
Cada valor debe ser **atómico**: una columna guarda un dato simple, no una colección:
-- mal: la colección de autores dentro de la fila del libro
CREATE TABLE book (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(200) NOT NULL,
author_names VARCHAR(400) NOT NULL -- 'Robert Martin, Martin Fowler'
);
Tampoco valen los **grupos repetitivos**: columnas gemelas tipo ''author1'', ''author2''..., que obligan a estimar cuántas hacen falta y dejan huecos vacíos.
La solución es la del modelo relacional: las colecciones se convierten en **tablas**. En este caso, la tabla de unión ''book_author'' vista en el tema 01.
===== 3. Segunda forma normal (2FN) =====
Con **clave primaria compuesta**, cada columna debe depender de la clave **completa**, no de una parte:
CREATE TABLE book_author (
book_id BIGINT NOT NULL,
author_id BIGINT NOT NULL,
author_nationality VARCHAR(80), -- depende solo de author_id
PRIMARY KEY (book_id, author_id)
);
''author_nationality'' cambia con el **autor**, no con el par (libro, autor): se repetiría en todos los libros de un autor y una actualización a medias lo rompería. La columna pertenece a la tabla ''author'', cuya clave es la que la determina.
===== 4. Tercera forma normal (3FN) =====
Cada columna debe depender **solo de la clave primaria**, no de otra columna no clave (dependencia **transitiva**). En la tabla del apartado 1: ''id'' → ''publisher_city'' → ''publisher_name''.
La corrección crea una tabla para la editorial y deja en ''book'' solo la clave foránea:
CREATE TABLE publisher (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
city VARCHAR(100) NOT NULL
);
CREATE TABLE book (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(200) NOT NULL,
price DECIMAL(10,2) NOT NULL,
publisher_id BIGINT NOT NULL,
FOREIGN KEY (publisher_id) REFERENCES publisher (id)
);
Cada dato se guarda una sola vez: la editorial existe por sí misma y sus libros la referencian.
===== 5. Resumen =====
^ Forma ^ Comprueba que ^ Solución típica ^
| **1FN** | Los valores son atómicos | Tabla propia para la colección |
| **2FN** | Con clave compuesta, todo depende de la clave completa | La columna se va con la tabla de la parte que la determina |
| **3FN** | Nadie depende de otra columna no clave | Tabla propia para la entidad dependiente |
El diseño sale del diagrama de clases y la traducción del tema 01 ya suele dar tablas casi normalizadas. Repasar 1FN–3FN es la comprobación final: si algo falla, falta — o sobra — una entidad o un atributo en el diagrama.