Normalización de Bases de Datos
1NF 2NF 3NF con un ejemplo simple
🌟 ¿Qué es normalizar?
Limpiar el diseño de las tablas para evitar duplicaciones y anomalías (insertar, actualizar, borrar).
Lo haremos paso a paso : 1NF → 2NF → 3NF.
🧩 Caso de ejemplo (sin normalizar)
| id_est | nombre_est | cursos | créditos | profs |
| ------ | ----------- | ----------------------- | -------- | ------------- |
| 1 | Ana Ruiz | Cálculo I, Probabilidad | 4 , 3 | López, García |
| 2 | Carlos León | Programación | 2 | Pérez |
Tabla: Inscripciones (todo metido en una sola tabla)
🧩 Caso de ejemplo (sin normalizar)
| id_est | nombre_est | cursos | créditos | profs
| ------ | ----------- | ----------------------- | -------- | ------------- |
| 1 | Ana Ruiz | Cálculo I, Probabilidad | 4 , 3 | López, García |
| 2 | Carlos León | Programación | 2 | Pérez |
👀 Problemas:
Listas en una celda (cursos, créditos, profs).
🧩 Caso de ejemplo (sin normalizar)
| id_est | nombre_est | cursos | créditos | profs |
| ------ | ----------- | ----------------------- | -------- | ------------- |
| 1 | Ana Ruiz | Cálculo I, Probabilidad | 4 , 3 | López, García |
| 2 | Carlos León | Programación | 2 | Pérez |
🧩 Caso de ejemplo (sin normalizar)
| id_est | nombre_est | curso | credito | prof |
| ------ | ----------- | ------------ | ------- | ------ |
| 1 | Ana Ruiz | Cálculo I | 4 | López |
| 1 | Ana Ruiz | Probabilidad | 3 | García |
| 2 | Carlos León | Programación | 2 | Pérez |
🧩 Caso de ejemplo (sin normalizar)
| id_est | nombre_est | curso | credito | prof |
| ------ | ----------- | ------------ | ------- | ------ |
| 1 | Ana Ruiz | Cálculo I | 4 | López |
| 1 | Ana Ruiz | Probabilidad | 3 | García |
| 2 | Carlos León | Programación | 2 | Pérez |
Solución: “descomponer” en filas (una por curso inscrito).
🧩 Caso de ejemplo (sin normalizar)
| id_est | nombre_est | curso | credito | prof |
| ------ | ----------- | ------------ | ------- | ------ |
| 1 | Ana Ruiz | Cálculo I | 4 | López |
| 1 | Ana Ruiz | Probabilidad | 3 | García |
| 2 | Carlos León | Programación | 2 | Pérez |
✨ Mejor: ya no hay listas.
🧩 Caso de ejemplo (sin normalizar)
| id_est | nombre_est | curso | credito | prof |
| ------ | ----------- | ------------ | ------- | ------ |
| 1 | Ana Ruiz | Cálculo I | 4 | López |
| 1 | Ana Ruiz | Probabilidad | 3 | García |
| 2 | Carlos León | Programación | 2 | Pérez |
⚠️ Aún hay repetición (nombre_est en varias filas).
🧩 Modelo relacional original
erDiagram
ESTUDIANTE {
INT id_est
STRING nombre
STRING apellido
INT email
CHAR fecha_registro
}
CURSO {
STRING id_curso
STRING nombre
INT precio
CHAR etiquetas
CHAR profesores
}
INSCRIPCION {
INT id_est
DOUBLE precio
DATE fecha
}
ESTUDIANTE ||--o{ INSCRIPCION : inscribe
CURSO ||--o{ INSCRIPCION : recibe
🧩 etiquetas es multivaluado
| id_curso | nombre | precio | etiquetas |
|----------|---------------|--------|-----------------------|
| CUR001 | SQL Básico | 300000 | Bases, Datos, Query |
| CUR002 | Java Inicial | 400000 | Programación, Objetos |
| CUR003 | Python Pro | 500000 | Datos, Ciencia |
→ violación de 1NF (una celda = un solo valor).
💡 Quitamos etiquetas de CURSO , pero aún no la hemos representado en otra tabla.
erDiagram
ESTUDIANTE {
INT id_est
STRING nombre
STRING apellido
INT email
CHAR fecha_registro
}
CURSO {
STRING id_curso
STRING nombre
INT precio
CHAR profesores
}
INSCRIPCION {
INT id_est
DOUBLE precio
DATE fecha
}
ESTUDIANTE ||--o{ INSCRIPCION : inscribe
CURSO ||--o{ INSCRIPCION : recibe
erDiagram
ESTUDIANTE {
INT id_est
STRING nombre
STRING apellido
INT email
CHAR fecha_registro
}
CURSO {
STRING id_curso
STRING nombre
INT precio
CHAR profesores
}
INSCRIPCION {
INT id_est
DOUBLE precio
DATE fecha
}
ETIQUETA {
STRING id_etiqueta
STRING nombre
}
CURSO_ETIQUETA {
STRING id_curso
STRING id_etiqueta
}
ESTUDIANTE ||--o{ INSCRIPCION : inscribe
CURSO ||--o{ INSCRIPCION : recibe
erDiagram
ESTUDIANTE {
INT id_est
STRING nombre
STRING apellido
INT email
CHAR fecha_registro
}
CURSO {
STRING id_curso
STRING nombre
INT precio
CHAR profesores
}
INSCRIPCION {
INT id_est
DOUBLE precio
DATE fecha
}
ETIQUETA {
STRING id_etiqueta
STRING nombre
}
CURSO_ETIQUETA {
STRING id_curso
STRING id_etiqueta
}
ESTUDIANTE ||--o{ INSCRIPCION : inscribe
CURSO ||--o{ INSCRIPCION : recibe
CURSO ||--o{ CURSO_ETIQUETA : tiene
ETIQUETA ||--o{ CURSO_ETIQUETA : pertenece
| id_curso | nombre | precio | etiquetas |
|----------|---------------|--------|-----------------------|
| CUR001 | SQL Básico | 300000 | Bases, Datos, Query |
| CUR002 | Java Inicial | 400000 | Programación, Objetos |
| CUR003 | Python Pro | 500000 | Datos, Ciencia |
| id_curso | nombre | precio |
|:----------|:--------------|-------:|
| CUR001 | SQL Básico | 300000 |
| CUR002 | Java Inicial | 400000 |
| CUR003 | Python Pro | 500000 |
| id_curso | id_etiqueta |
|-----------|--------------|
| CUR001 | ETQ01 |
| CUR001 | ETQ02 |
| CUR001 | ETQ03 |
| CUR002 | ETQ04 |
| CUR002 | ETQ05 |
| CUR003 | ETQ02 |
| CUR003 | ETQ06 |
| id_etiqueta | nombre |
|:-------------|:-------------|
| ETQ01 | Bases |
| ETQ02 | Datos |
| ETQ03 | Query |
| ETQ04 | Programación |
| ETQ05 | Objetos |
| ETQ06 | Ciencia |
En pocas palabras: cada columna debe describir únicamente al objeto principal de la tabla, y no depender de otras columnas distintas a su identificador.
Cuando una tabla mezcla información de diferentes entidades (por ejemplo, cursos y profesores), aparecen redundancias y anomalías de actualización .
🧩 Ejemplo
Supongamos que tenemos la siguiente estructura:
CURSO {
STRING id_curso
STRING nombre
INT precio
CHAR profesores
}
🧩 Ejemplo
Y los datos lucen así:
| id_curso | nombre | precio | profesores |
|-----------|----------------|--------|-------------|
| C01 | SQL Básico | 300000 | López |
| C02 | SQL Intermedio | 400000 | López |
| C03 | Python Pro | 500000 | García |
💬 ¿Qué problema hay?
A simple vista, el profesor “López” aparece varias veces.
Información del profesor está repetida .
Si el profesor cambia su nombre o apellido, deberíamos modificarlo en todas las filas . Eso genera redundancia y posibles inconsistencias .
⚠️ ¿Por qué no está en 2NF?
Aunque id_curso identifica bien cada curso, la columna profesores no describe directamente al curso , sino a otra entidad: el profesor que lo dicta.
Por tanto, esta tabla viola la 2NF , porque contiene información que depende de algo externo al curso.
📘 CURSO
| id_curso | nombre | precio |
|-----------|----------------|---------|
| C01 | SQL Básico | 300000 |
| C02 | SQL Intermedio | 400000 |
| C03 | Python Pro | 500000 |
👨🏫 PROFESOR
| id_prof | nombre_prof |
|----------|-------------|
| P01 | López |
| P02 | García |
🧾 IMPARTE
| id_prof | id_curso |
|----------|----------|
| P01 | C01 |
| P01 | C02 |
| P02 | C03 |
✅ Resultado (ya en 2NF)
Ahora:
Cada tabla representa una sola entidad (curso o profesor).
No hay duplicación de nombres de profesores.
Si cambia un profesor, se actualiza solo una vez .
Los datos son más coherentes, limpios y fáciles de mantener .
✨ ¡La base ya cumple con la Segunda Forma Normal (2NF) !
💼 Ejemplo 1 — Facturas con balance
| id_factura | total | pagos | balance | ganancias | |-------------|--------|--------|----------|------------|
| F001 | 1000 | 700 | 300 | 200 |
| F002 | 800 | 500 | 300 | 150 |
| F003 | 1200 | 1200 | 0 | 350 |
⚠️ ¿Qué problema hay?
| id_factura | total | pagos | balance | ganancias | |-------------|--------|--------|----------|------------|
| F001 | 1000 | 700 | 300 | 200 |
| F002 | 800 | 500 | 300 | 150 |
| F003 | 1200 | 1200 | 0 | 350 |
\(\text{balance} = \text{total} - \text{pagos}\)
Solución (en 3NF)
| id_factura | total | pagos | ganancias |
|-------------|--------|--------|------------|
| F001 | 1000 | 700 | 200 |
| F002 | 800 | 500 | 150 |
| F003 | 1200 | 1200 | 350 |
Así la tabla cumple la 3NF ✨ -
Guardamos solo los datos base , no los derivados:
–
👥 Ejemplo 2 — Nombres y apellidos
| id_cliente | nombre_completo | nombre | apellido | |-------------|--------------------|---------|-----------|
| C001 | Ana Ruiz | Ana | Ruiz |
| C002 | Carlos León | Carlos | León |
Mini checklist de normalización
1NF: ¿Hay listas o campos multivalor en una celda? → romper en filas .
2NF: Si la PK es compuesta, ¿hay atributos que dependan de una sola parte ? → separar .
3NF: ¿Algún atributo no clave depende de otro no clave ? → factorizar . -
–
Mensaje final
Normalizar es separar lo que depende de cosas diferentes, Para que los datos sean coherentes , fáciles de mantener y consultar .