Normalización: poner orden en los datos

Imagine una tabla universitaria donde una celda enumera todos los cursos de un estudiante separados por comas, y el teléfono y la dirección se mezclan. Si alguien cambia su apellido o se muda, tendrías que buscar y arreglar esa cadena en muchos lugares. La normalización es la división deliberada de datos en tablas y relaciones para eliminar duplicaciones, evitar contradicciones y simplificar el mantenimiento de la base de datos.

¿Por qué molestarse? Tres clases de anomalías
Abrir una tarjeta: lo que se rompe sin normalización
El camino de normalización: 1NF → 2NF → 3NF
Haga clic en los pasos: orden de descomposición
1FN
Atomicidad: eliminar listas dentro de las celdas
2FN
Clave completa: eliminar dependencias parciales
3NF
Solo desde la clave: eliminar dependencias transitivas
Primera forma normal (1NF)

La regla 1NF es simple: cada celda contiene un valor indivisible de un dominio. No hay "listas separadas por comas" en un campo; use filas separadas o una tabla separada para eso.

Corrección 1NF – versión “anterior”
sql
1
-- Bad: 1NF violation — multiple phones in one cell
2
CREATE TABLE students_bad (
3
    id          SERIAL PRIMARY KEY,
4
    full_name   TEXT NOT NULL,
5
    phones      TEXT  -- '+7999..., +7911...'
6
);
Corrección 1NF – versión “después”
sql
1
-- Good: 1NF — one phone per row
2
CREATE TABLE students (
3
    id        SERIAL PRIMARY KEY,
4
    full_name TEXT NOT NULL
5
);
6
CREATE TABLE student_phones (
7
    id         SERIAL PRIMARY KEY,
8
    student_id INT NOT NULL REFERENCES students(id),
9
    phone      TEXT NOT NULL
10
);
Segunda forma normal (2NF)

2NF importa cuando la clave principal es compuesta. Cada atributo que no sea clave debe depender de la clave completa, no de parte de ella. Si la clave es el par "estudiante + curso", entonces la duración del curso depende únicamente del curso: almacenarlo en la fila de inscripción significa copiar el mismo valor y correr el riesgo de desviarse.

Corrección 2NF – versión “anterior”
sql
1
-- Bad: partial dependency on a composite key
2
CREATE TABLE enrollments_bad (
3
    student_id   INT NOT NULL,
4
    course_id    INT NOT NULL,
5
    enrolled_at  DATE NOT NULL,
6
    course_duration_hours INT NOT NULL, -- duplicate per student
7
    PRIMARY KEY (student_id, course_id)
8
);
Corrección 2NF – versión “después”
sql
1
-- Good: duration stored once, in the course catalog
2
CREATE TABLE courses (
3
    id          SERIAL PRIMARY KEY,
4
    title       TEXT NOT NULL,
5
    duration_hours INT NOT NULL
6
);
7
CREATE TABLE enrollments (
8
    student_id  INT NOT NULL,
9
    course_id   INT NOT NULL REFERENCES courses(id),
10
    enrolled_at DATE NOT NULL,
11
    PRIMARY KEY (student_id, course_id)
12
);
Tercera forma normal (3NF)

3NF prohíbe las dependencias transitivas: una columna sin clave no debe depender de otra columna sin clave. Si un estudiante tiene "cityid" y "cityname" está duplicado junto a él, el nombre de la ciudad depende del identificador de la ciudad, no de la clave principal del estudiante. El nombre debe estar en una tabla de búsqueda separada.

Corrección 3NF – versión “anterior”
sql
1
-- Bad: city_name depends transitively on city_id, not on student id
2
CREATE TABLE students_bad_city (
3
    id         SERIAL PRIMARY KEY,
4
    full_name  TEXT NOT NULL,
5
    city_id    INT NOT NULL,
6
    city_name  TEXT NOT NULL  -- duplicate lookup
7
);
Corrección 3NF – versión “después”
sql
1
-- Good: city lookup; student has only city_id
2
CREATE TABLE cities (
3
    id        SERIAL PRIMARY KEY,
4
    name      TEXT NOT NULL
5
);
6
CREATE TABLE students (
7
    id        SERIAL PRIMARY KEY,
8
    full_name TEXT NOT NULL,
9
    city_id   INT NOT NULL REFERENCES cities(id)
10
);
hoja de trucos

1NF • 2NF • 3NF de un vistazo

La normalización no es un dogma ni una división interminable: elimina la redundancia hasta que las anomalías de inserción, eliminación y actualización dejan de amenazar los datos. Para enseñar esquemas OLTP, 3NF suele ser un punto de partida razonable.
1NF: valor indivisible en cada celda
2NF: los atributos que no son clave dependen de toda la clave primaria
3NF: los atributos que no son clave dependen solo de la clave, no entre sí
Menos copias redundantes: menos desvío y mantenimiento más sencillo