Normalización

Bases de Datos

02

Aviso Importante

Este es un material de apoyo no oficial, desarrollado por alumnos con la ayuda de inteligencia artificial. No representa la posición oficial de la institución ni de los profesores.
No cuestione ni moleste a los profesores sobre este contenido. El material está basado en apuntes tomados durante las clases e investigaciones complementarias hechas por los propios alumnos.
Este material puede contener imprecisiones. En caso de duda, consulte siempre el material oficial proporcionado por el profesor y las referencias al final.
Sugerencias y Correcciones
¿Encontraste un error o tienes una sugerencia? Envía tu contribución por el grupo de WhatsApp de la clase. Toda colaboración es bienvenida para mejorar el material para todos.
03
ÍNDICE

Contenido

04
INTRODUCCIÓN

¿Qué es la Normalización?

Imagina una hoja de cálculo donde una celda contiene múltiples valores separados por barras — como almacenar varios números de artículo, descripciones y precios todos en una sola fila. Esa es una tabla no normalizada, y hace que actualizar, buscar y mantener los datos sea una pesadilla. La normalización es el proceso paso a paso de reorganizar esa tabla desordenada en un conjunto de tablas bien estructuradas que eliminan la redundancia y protegen la integridad de los datos.

El proceso sigue una serie de formas normales, cada una construida sobre la anterior. La Primera Forma Normal (1NF) asegura que cada celda contiene un solo valor atómico — sin grupos repetitivos. La Segunda Forma Normal (2NF) elimina las dependencias parciales, donde un atributo no clave depende de solo una parte de una clave compuesta. La Tercera Forma Normal (3NF) elimina las dependencias transitivas, donde un atributo no clave depende de otro atributo no clave en lugar de la clave primaria.

Piénsalo como organizar un archivero desordenado: la 1NF asegura que cada cajón tiene un tipo de documento, la 2NF asegura que los documentos estén archivados bajo la categoría correcta, y la 3NF mueve la información referenciada a su propio cajón dedicado. Al final, cada dato existe en exactamente un lugar — actualízalo una vez y es correcto en todas partes.

En esta lección, recorreremos dos ejemplos completos — un sistema de pedidos de hardware y un sistema de visitas hospitalarias — transformando cada uno de una tabla caótica en un conjunto limpio de tablas normalizadas en 3NF. En el camino, aprenderás a identificar claves primarias, claves foráneas, claves compuestas y las dependencias que impulsan cada paso de normalización.

05
DIAGRAMA

UNF a 1NF — Eliminación de Grupos Repetitivos

Ejemplo de pedido de hardware: un valor por celda, un hecho por fila

El problema: Una empresa de hardware almacena pedidos en una sola tabla. Cuando un pedido tiene varios artículos, los detalles se agrupan en una celda separados por barras — X3412/X2189. Esto viola la 1NF porque cada celda debe contener exactamente un valor.

Cómo identificarlo: Observa cada celda de tu tabla. ¿Alguna celda contiene más de un valor (separados por comas, barras o listados verticalmente)? Si es así, esos atributos forman un grupo repetitivo. La solución es siempre la misma: mueve los atributos repetidos a una nueva tabla, dale un nombre significativo y enlázala usando la clave primaria original como clave foránea.
✗ Antes — UNF (grupos repetitivos en naranja)
Order NoDateCust NoNameItem NoDescriptionCostQty
100105-Feb0123AmalX3412/X2189120Gb HD/Cisco NIC40/205/25
100210-Feb0345AliY7674/B3456/F6758417" Monitor/Wireless Mouse/2GB Ram50/10/806/10/7
⬇ Primero: expandir cada valor en su propia fila
1NF — Todos los valores atómicos (uno por celda)
Order NoDateCust NoNameAddressContactItem NoDescriptionCostQty
100105-Feb0123AmalDublin39112200X3412120Gb HD405
100105-Feb0123AmalDublin39112200X2189Cisco NIC2025
100210-Feb0345AliMeath3321001Y767417" Monitor506
100210-Feb0345AliMeath3321001B3456Wireless Mouse1010
100210-Feb0345AliMeath3321001F675842GB Ram807
Observa la redundancia: Los datos de Amal (nombre, dirección, contacto) se repiten para cada artículo del pedido 1001. Los datos de Ali se repiten tres veces para el pedido 1002. Esto ya está en 1NF (un valor por celda), pero los datos repetidos desperdician espacio y crean problemas de actualización. Siguiente: dividir en ORDER (datos del pedido) y ORDER_ITEM (datos de artículos por pedido), enlazados por Order Number como clave foránea.
⬇ Dividir en dos tablas para reducir la redundancia
✓ Tabla ORDER
Order No (PK)DateCust NoNameAddressContact
100105-Feb-20240123AmalDublin39112200
100210-Feb-20240345AliMeath3321001
✓ Tabla ORDER_ITEM (nueva)
Order No (FK)Item No (PK)DescriptionCostQty
1001X3412120Gb HD405
1001X2189Cisco NIC2025
1002Y767417" Monitor506
1002B3456Wireless Mouse1010
1002F675842GB Ram807
Resultado: La clave compuesta de ORDER_ITEM es (Order Number + Item Number) — ninguno por sí solo puede identificar una fila de forma única. Order Number también es una clave foránea que enlaza con ORDER.

Las columnas de artículos repetidos (naranja) se mueven a su propia tabla. Cada artículo ahora tiene su propia fila, y las dos tablas se enlazan por Order Number.

06
DIAGRAMA

1NF a 2NF — Eliminación de Dependencias Parciales

Ejemplo de pedido de hardware: Description y Unit Cost dependen solo de Item Number

El problema: Después de la 1NF, ORDER_ITEM tiene una clave compuesta (Order Number + Item Number). Pero Description y Unit Cost solo dependen de Item Number — no tienen nada que ver con el pedido. Esto se llama una dependencia parcial.

Cómo identificarlo: Primero, verifica si alguna tabla tiene una clave compuesta (dos o más columnas formando la clave primaria). Si la tiene, pregúntate para cada atributo no clave: "¿Este atributo necesita AMBAS partes de la clave para ser identificado, o solo una?" Si la respuesta es "solo una", ese atributo tiene una dependencia parcial y debe moverse a su propia tabla. Aquí, "¿Cómo se llama el artículo X3412?" solo necesita Item Number — no importa a qué pedido pertenece.
✗ Dependencia Parcial Detectada
CLAVE COMPUESTA
Order No + Item No
DEPENDE SOLO DE ITEM NO ✗
Description, Unit Cost
|
DEPENDE DE LA CLAVE COMPLETA ✓
Quantity
⬇ Aplicar 2NF: mover los atributos parcialmente dependientes
✓ ORDER_ITEM (actualizada)
Order No (FK)Item No (FK)Qty
1001X34125
1001X218925
1002Y76746
1002B345610
1002F675847
✓ ITEM (nueva tabla)
Item No (PK)DescriptionUnit Cost
X3412120Gb HD40
X2189Cisco NIC20
Y767417" Monitor50
B3456Wireless Mouse10
F675842GB Ram80
Resultado: Ahora tenemos tres tablas — ORDER, ORDER_ITEM e ITEM. Item Number se convierte en una clave foránea en ORDER_ITEM que referencia la tabla ITEM. Ningún atributo depende ya de solo una parte de la clave.

Description y Unit Cost se mueven a ITEM porque dependen solo de Item Number, no de la clave compuesta completa.

07
DIAGRAMA

2NF a 3NF — Eliminación de Dependencias Transitivas

Ejemplo de pedido de hardware: Name, Address y Contact dependen de Customer Number, no de Order Number

El problema: La tabla ORDER todavía contiene Name, Address y Contact Number. Estos atributos no dependen de Order Number (la clave primaria) — dependen de Customer Number, que es un atributo no clave. Esta cadena se llama una dependencia transitiva: Order Number → Customer Number → Name/Address/Contact.

Cómo identificarlo: Para cada atributo no clave, pregunta: "¿Este atributo describe directamente la clave primaria, o describe otro atributo no clave?" Si Name describe Customer Number (no Order Number), tienes una dependencia transitiva. La prueba práctica: "Si cambio este valor, ¿estaría mal en otras filas?" Si Amal se muda de Dublin a Cork, cada pedido que hizo mostraría la dirección incorrecta — eso significa que la dirección pertenece a su propia tabla.
✗ Cadena de Dependencia Transitiva
CLAVE PRIMARIA
Order No
NO CLAVE/div>
Customer No
DEPENDE DE CUST NO ✗
Name, Address, Contact
⬇ Aplicar 3NF: mover los atributos transitivamente dependientes
✓ ORDER (actualizada)
Order No (PK)Cust No (FK)Order Date
1001012305-Feb-2024
1002034510-Feb-2024
✓ CUSTOMER (nueva tabla)
Cust No (PK)NameAddressContact
0123AmalDublin39112200
0345AliMeath3321001
✓ Esquema final — 4 tablas en 3NF
ORDER
Order No (PK)Cust No (FK)Date
1001012305-Feb-2024
1002034510-Feb-2024
CUSTOMER
Cust No (PK)NameAddressContact
0123AmalDublin39112200
0345AliMeath3321001
ITEM
Item No (PK)DescriptionCost
X3412120Gb HD40
X2189Cisco NIC20
Y767417" Monitor50
B3456Wireless Mouse10
F675842GB Ram80
ORDER_ITEM
Order No (FK)Item No (FK)Qty
1001X34125
1001X218925
1002Y76746
1002B345610
1002F675847
Resultado: Cuatro tablas, cada una almacenando un tipo de dato. Si Amal cambia de dirección, se actualiza una fila en CUSTOMER. Si el precio de un artículo cambia, se actualiza una fila en ITEM. No queda redundancia.

El resultado completo en 3NF: ORDER, CUSTOMER, ITEM y ORDER_ITEM — cuatro tablas sin redundancia, sin dependencias parciales y sin dependencias transitivas.

08
DIAGRAMA

Pedido de Hardware — Relaciones entre Tablas

Cómo las cuatro tablas en 3NF se conectan mediante claves foráneas

1N1NN1CUSTOMERcustomer_numberPKnameaddresscontact_numberORDERorder_numberPKcustomer_numberFKorder_dateORDER_ITEMorder_numberFKitem_numberFKquantityITEMitem_numberPKdescriptionunit_cost
09
DIAGRAMA

Sistema de Visitas Hospitalarias — Paso a Paso

Aplicando la lista de verificación de tres pasos a datos de salud

Segundo ejemplo — Visitas hospitalarias: Un hospital registra visitas de pacientes con detalles de tratamiento. En la tabla original, una fila almacena todos los tratamientos de una visita (e.g. "X-Ray, Dr Smith, Radiology, €120; Blood Test, Dr John, Pathology, €50"). Después de aplicar 1NF (valores atómicos), 2NF (sin dependencias parciales) y 3NF (sin dependencias transitivas), los datos se dividen en cinco tablas limpias. Cada dato — nombres de pacientes, departamentos de médicos, costos de tratamientos — se almacena en exactamente un lugar.
✗ UNF — Detalles de tratamiento agrupados en una celda
VisitIDPatientDateTreatments
V101Ali Khan2026-03-10X-Ray (Dr Smith, Radiology, €120), Blood Test (Dr John, Pathology, €50)
V102Sara Noor2026-03-11MRI Scan (Dr Lee, Imaging, €300), ECG (Dr Patel, Cardiology, €90)
V103Emma Cole2026-03-12Consulta (Dr Patel, Cardiología, €80), Radiografía (Dr Smith, Radiología, €120)
Paso 1 — 1NF: La columna Treatments tiene múltiples valores en una celda. Cómo identificarlo: las comas y los paréntesis nos indican que el nombre del tratamiento, médico, departamento y costo están todos agrupados. Solución: dar a cada tratamiento su propia fila. Clave compuesta = (VisitID, TreatmentName).
⬇ Resultado 1NF
VisitIDPatientIDPatientNameDateTreatmentDoctorDeptCost
V101P01Ali Khan2026-03-10X-RayDr SmithRadiology€120
V101P01Ali Khan2026-03-10Blood TestDr JohnPathology€50
V102P02Sara Noor2026-03-11ResonanciaDr LeeImagen€300
V102P02Sara Noor2026-03-11ECGDr PatelCardiología€90
V103P03Emma Cole2026-03-12ConsultaDr PatelCardiología€80
V103P03Emma Cole2026-03-12RadiografíaDr SmithRadiología€120
Paso 2 — 2NF: La clave compuesta es (VisitID + TreatmentName). Pregunta para cada columna: ¿necesita AMBAS partes? PatientID, PatientName y Date solo necesitan VisitID — son iguales independientemente del tratamiento. Eso es una dependencia parcial. Solución: mover los datos de visita/paciente a una tabla VISITS.
⬇ Resultado 2NF
VISITS
VisitIDPatientIDNameDate
V101P01Ali Khan2026-03-10
V102P02Sara Noor2026-03-11
V103P03Emma Cole2026-03-12
VISIT_TREATMENTS
VisitID (FK)TreatmentDoctorDeptCost
V101X-RayDr SmithRadiology€120
V101Blood TestDr JohnPathology€50
V102ResonanciaDr LeeImagen€300
V102ECGDr PatelCardiología€90
V103ConsultaDr PatelCardiología€80
V103RadiografíaDr SmithRadiología€120
Paso 3 — 3NF: En VISITS, PatientName depende de PatientID (no de VisitID) — dependencia transitiva. En VISIT_TREATMENTS, Doctor y Dept describen al médico (no la visita), y Cost describe el tratamiento (no la visita). Pregunta: "Si Dr Patel cambia de departamento, ¿cuántas filas hay que actualizar?" Varias — entonces hay que extraer. Solución: crear las tablas PATIENTS, DOCTORS y TREATMENTS.
⬇ Resultado 3NF — cinco tablas
Patients
PatientIDName
P01Ali Khan
P02Sara Noor
P03Emma Cole
Visits
VisitIDPatientID (FK)Date
V101P012026-03-10
V102P022026-03-11
V103P032026-03-12
Doctors
DoctorIDNameDept
D01Dr SmithRadiology
D02Dr JohnPathology
D03Dr LeeImaging
D04Dr PatelCardiology
Treatments
TreatmentIDNameCost
T01X-Ray€120
T02Blood Test€50
T03MRI Scan€300
T04ECG€90
T05Consultation€80
VisitTreatments
VisitID (FK)TreatmentID (FK)DoctorID (FK)
V101T01D01
V101T02D02
V102T03D03
V102T04D04
V103T05D04
V103T01D01
Idea clave: Las mismas tres reglas se aplican independientemente del dominio. Pregúntate: ¿Este atributo depende de toda la clave, solo de una parte, o de otro atributo no clave? La respuesta te indica qué forma normal aplicar.

El ejemplo hospitalario produce cinco tablas en 3NF. Cada dato se almacena una vez — actualizar el departamento de un médico o el costo de un tratamiento requiere cambiar solo una fila.

10
DIAGRAMA

Sistema de Visitas Hospitalarias — Relaciones entre Tablas

Cómo las cinco tablas en 3NF se conectan mediante claves foráneas

1N1N1NN1PATIENTSPatientIDPKPatientNameVISITSVisitIDPKPatientIDFKVisitDateDOCTORSDoctorIDPKDoctorNameDepartmentVISIT_TREATMENTSVisitIDFKTreatmentIDFKDoctorIDFKTREATMENTSTreatmentIDPKTreatmentNameCost
11
DIAGRAMA

Cómo Identificar Dónde Dividir Tablas

Una lista de verificación de tres pasos para cada forma normal

La pregunta clave en cada etapa: La normalización consiste en hacer una pregunta por etapa. Si la respuesta es "sí", divides. Si es "no", pasas a la siguiente etapa. Aquí está la lista de verificación que puedes seguir para cualquier tabla en cualquier dominio.
1
Verificar 1NF — ¿Hay grupos repetitivos?
Pregunta: ¿Alguna celda contiene más de un valor?
Busca: Barras (X3412/X2189), listas separadas por comas, múltiples filas de datos agrupadas en una celda.
Si SÍ: Primero, expande cada celda con múltiples valores en su propia fila — obtienes una gran tabla plana donde cada celda es atómica. Luego observa la redundancia (datos que se repiten entre filas) y divide los atributos repetidos en una nueva tabla. Usa la PK original como clave foránea en la nueva tabla y crea una clave compuesta (PK original + PK del nuevo atributo).
Si NO: La tabla ya está en 1NF — procede al paso 2.
2
Verificar 2NF — ¿Alguna dependencia parcial?
Pregunta: ¿Hay una clave compuesta? ¿Algún atributo no clave depende de solo parte de ella?
Prueba: Para cada columna no clave, pregunta: "¿Necesito AMBAS partes de la clave compuesta para buscar este valor?"
Si SÍ (existe dep. parcial): Mueve los atributos parcialmente dependientes a una nueva tabla, con clave en la parte de la que dependen.
Si NO (o sin clave compuesta): La tabla ya está en 2NF — procede al paso 3.
3
Verificar 3NF — ¿Alguna dependencia transitiva?
Pregunta: ¿Algún atributo no clave depende de otro atributo no clave en lugar de la clave primaria?
Prueba: Para cada columna no clave, pregunta: "¿Esto describe la PK directamente, o describe una columna diferente?"
Prueba práctica: "Si actualizo este valor, ¿otras filas se volverían inconsistentes?"
Si SÍ (existe dep. transitiva): Mueve los atributos transitivamente dependientes a una nueva tabla. Mantén la columna intermediaria como FK.
Si NO: ¡Felicitaciones — tu tabla está en 3NF!

Aplica estas tres verificaciones en orden a cualquier tabla. Cada paso se basa en el anterior — debes lograr la 1NF antes de verificar la 2NF, y la 2NF antes de verificar la 3NF.

12
DIAGRAMA

Ejemplo Resuelto — Sistema de Cursos de Profesores

Normalizando un horario universitario de UNF a 3NF

Third example: Una universidad almacena datos de profesores y cursos en una sola tabla. Cada profesor imparte múltiples cursos, por lo que los detalles de los cursos se repiten. Apliquemos los mismos trespasos de verificación.
✗ UNF — Grupos de cursos repetitivos
Lect NoNameFacultyOfficeCourse CodeCourse NameStart DateWeekly Hrs
7146JamesBusinessRoom 22BM01Buss Manage12/9/20234
A01Account11/9/20233
E01Economics30/9/20237
1463DenisITRoom 21CS01Computer Systems01/9/20236
P01Programming02/9/20235
6455PhilBusinessRoom 22BM01Buss Manage04/10/20234
M01Marketing10/10/20236
⬇ Paso 1: Expandir cada valor en su propia fila
1NF — Todos los valores atómicos (uno por celda)
Lect NoNameFacultyOfficeCourse CodeCourse NameStartHrs
7146JamesBusinessRoom 22BM01Buss Manage12/9/234
7146JamesBusinessRoom 22A01Account11/9/233
7146JamesBusinessRoom 22E01Economics30/9/237
1463DenisITRoom 21CS01Comp Systems01/9/236
1463DenisITRoom 21P01Programming02/9/235
6455PhilBusinessRoom 22BM01Buss Manage04/10/234
6455PhilBusinessRoom 22M01Marketing10/10/236
Observa la redundancia: Los datos de James (nombre, facultad, oficina) se repiten para cada uno de sus 3 cursos. Denis se repite dos veces, Phil se repite dos veces. Esto desperdicia espacio y crea probleme problems — if James changes office, three rows need updating. Next: dividir en LECTURER (datos del profesor) y LECTURER_COURSE (asignaciones de cursos), enlazados por Lect No como clave foránea.
⬇ Dividir en dos tablas para reducir la redundancia
✓ LECTURER
Lect No (PK)NameFacultyOffice
7146JamesBusinessRoom 22
1463DenisITRoom 21
6455PhilBusinessRoom 22
✓ LECTURER_COURSE (clave compuesta)
Lect No (FK)Course CodeCourse NameStartHrs
7146BM01Buss Manage12/9/234
7146A01Account11/9/233
7146E01Economics30/9/237
1463CS01Comp Systems01/9/236
1463P01Programming02/9/235
6455BM01Buss Manage04/10/234
6455M01Marketing10/10/236
⬇ Paso 2: Aplicar 2NF
Dependencia parcial encontrada: Course Name depende solo de Course Code (no de la clave compuesta completa Lect No + Course Code). El mismo curso siempre tiene el mismo nombre independientemente de quién lo imparte. Fix: extraer la tabla COURSE.
✓ COURSE (new)
Code (PK)Name
BM01Buss Manage
A01Account
E01Economics
CS01Comp Systems
P01Programming
M01Marketing
✓ LECTURER_COURSE (actualizada)
Lect No (FK)Code (FK)Start DateWeekly Hrs
7146BM0112/9/234
7146A0111/9/233
7146E0130/9/237
1463CS0101/9/236
1463P0102/9/235
6455BM0104/10/234
6455M0110/10/236
⬇ Paso 3: Verificar 3NF
Verificar LECTURER: ¿Faculty u Office dependen de otro atributo no clave? Faculty describe al profesor directamente, y Office está asignada al profesor — no hay dependenciive dependency. Result: LECTURER ya está en 3NF.
✓ Esquema final — 3 tablas en 3NF
LECTURER
Lect No (PK)NameFacultyOffice
7146JamesBusinessRoom 22
1463DenisITRoom 21
6455PhilBusinessRoom 22
COURSE
Code (PK)Name
BM01Buss Manage
A01Account
E01Economics
CS01Comp Systems
P01Programming
M01Marketing
LECTURER_COURSE
Lect No (FK)Code (FK)StartHrs
7146BM0112/9/234
7146A0111/9/233
7146E0130/9/237
1463CS0101/9/236
1463P0102/9/235
6455BM0104/10/234
6455M0110/10/236

El ejemplo del profesor utiliza la misma lista de verificación de tres pasos. Course Name tenía una dependencia parcial de Course Code, pero no se encontró ninguna dependencia transitiva — se alcanzó la 3NF en el paso 2.

13
DIAGRAMA

Sistema de Cursos de Profesores — Relaciones entre Tablas

Cómo las tres tablas en 3NF se conectan mediante claves foráneas

1NN1LECTURERLect_NoPKNameFacultyOfficeLECTURER_COURSELect_NoFKCourse_CodeFKStart_DateWeekly_HrsCOURSECourse_CodePKCourse_Name
14
CÓDIGO

SQL — Paso 1: UNF a 1NF

Dividir la tabla ORDER en ORDER + ORDER_ITEM

step1_1nf.sql
-- STEP 1: UNF → 1NF
-- Remove repeating groups (item details) into a new table

CREATE TABLE "Order" (
    order_number     INT           PRIMARY KEY,
    order_date       DATE          NOT NULL,
    customer_number  VARCHAR(4)    NOT NULL,
    name             VARCHAR(50)   NOT NULL,
    address          VARCHAR(100)  NOT NULL,
    contact_number   VARCHAR(20)   NOT NULL
);

-- New table for the repeating item group
-- Composite key: order_number + item_number
CREATE TABLE Order_Item (
    order_number  INT          REFERENCES "Order",
    item_number   VARCHAR(10)  NOT NULL,
    description   VARCHAR(100) NOT NULL,
    unit_cost     DECIMAL(10,2) NOT NULL,
    quantity      INT          NOT NULL,
    PRIMARY KEY (order_number, item_number)
);
15
CÓDIGO

SQL — Paso 2: 1NF a 2NF

Extraer la tabla ITEM para eliminar la dependencia parcial

step2_2nf.sql
-- STEP 2: 1NF → 2NF
-- Description and unit_cost depend only on item_number
-- (partial dependency on the composite key)
-- Move them to a new ITEM table

CREATE TABLE Item (
    item_number  VARCHAR(10)   PRIMARY KEY,
    description  VARCHAR(100)  NOT NULL,
    unit_cost    DECIMAL(10,2) NOT NULL
);

-- Order_Item now only keeps quantity
-- (depends on the FULL composite key)
CREATE TABLE Order_Item (
    order_number  INT          REFERENCES "Order",
    item_number   VARCHAR(10)  REFERENCES Item,
    quantity      INT          NOT NULL,
    PRIMARY KEY (order_number, item_number)
);
16
CÓDIGO

SQL — Paso 3: 2NF a 3NF

Extraer la tabla CUSTOMER para eliminar la dependencia transitiva

step3_3nf.sql
-- STEP 3: 2NF → 3NF
-- Name, address and contact depend on customer_number
-- (transitive dependency — not on the PK)
-- Move them to a new CUSTOMER table

CREATE TABLE Customer (
    customer_number  VARCHAR(4)    PRIMARY KEY,
    name             VARCHAR(50)   NOT NULL,
    address          VARCHAR(100)  NOT NULL,
    contact_number   VARCHAR(20)   NOT NULL
);

-- Order now only keeps customer_number as FK
CREATE TABLE "Order" (
    order_number     INT           PRIMARY KEY,
    customer_number  VARCHAR(4)    REFERENCES Customer,
    order_date       DATE          NOT NULL
);

-- Final schema: 4 tables in 3NF
-- Customer, Order, Item, Order_Item
-- Each fact stored exactly once ✓
17
RESUMEN

Referencia Rápida

ConceptoReglaQué Hacer
UNFDatos crudos, puede tener grupos repetitivosIdentificar la entidad, listar todos los atributos, encontrar la clave
1NFSin atributos multivaluadosEliminar grupos repetitivos en una nueva tabla; agregar una clave foránea para enlazarlos
2NFSin dependencias parcialesSi existe una clave compuesta, mover los atributos que dependen de solo una parte
3NFSin dependencias transitivasMover atributos no clave que dependen de otros atributos no clave
Clave Primaria (PK)Identifica únicamente cada filaNo puede ser NULL; subrayada en la notación
Clave Foránea (FK)Referencia una PK en otra tablaCrea relaciones entre tablas
Clave CompuestaDos o más atributos formando una PKSe usa cuando ningún atributo es único por sí solo (ej. Order No + Item No)
18
EJERCICIOS

Ejercicios Prácticos

Pon a prueba tu comprensión de la normalización

01
Una tabla de profesores tiene las columnas: Lecturer_no, Name, Faculty, Office_loc, Course_code, Course_name, Start_date, Weekly_time. Un profesor puede impartir varios cursos. ¿Qué columnas forman el grupo repetitivo?
¿Qué atributos tienen múltiples valores para un solo profesor?
02
Después de eliminar el grupo repetitivo en una tabla LECTURER_COURSE, ¿cuál sería la clave compuesta de esa nueva tabla?
¿Qué dos atributos juntos identifican de manera única cada fila?
03
En el ejemplo de pedido de hardware, la tabla ORDER contiene Name, Address y Contact Number junto con Customer Number. ¿Qué tipo de dependencia tienen Name, Address y Contact Number, y qué forma normal se viola?
¿Estos atributos dependen de la clave primaria (Order Number) o de otro atributo no clave?
04
En el ejemplo de visitas hospitalarias, después de alcanzar la 1NF, la clave compuesta es (VisitID, TreatmentName). PatientName y VisitDate dependen solo de VisitID. ¿Qué forma normal se viola y por qué?
¿PatientName depende de la clave compuesta completa o solo de una parte?
05
¿Cuál es la diferencia entre una clave compuesta y una clave foránea?
06
Dada: BOOK(BookID, BookDesc, CategoryID, CategoryDesc). ¿Esta tabla está en 3NF? Si no, explica por qué y muestra la solución.
¿Cada atributo no clave depende directamente de BookID?
07
Fácil — Normaliza esta tabla de préstamos de biblioteca a 3NF.
LoanIDMemberNameMemberEmailBookTitleAuthorLoanDateReturnDate
L01Jane Doejane@mail.comSQL BasicsT. Brown01/03/2615/03/26
L02Jane Doejane@mail.comData DesignR. Singh05/03/2619/03/26
L03Mark Leemark@mail.comSQL BasicsT. Brown10/03/2624/03/26
¿Qué atributos describen al miembro? ¿Cuáles describen al libro? ¿Cuáles describen el préstamo en sí?
08
Medio — Normaliza esta tabla de reservas de gimnasio a 3NF.
BookingIDClientPhoneClassInstructorInst PhoneRoomDate
B01Anna555-1234YogaCoach Kim555-9999R110/03/26
B02Tom555-5678YogaCoach Kim555-9999R110/03/26
B03Anna555-1234PilatesCoach Lee555-8888R211/03/26
¿Phone depende de BookingID o del cliente? ¿Instructor Phone depende de BookingID o del instructor?
09
Medio-Difícil — Normaliza esta tabla de tienda en línea. Identifica todas las cadenas de dependencias.
PurchIDCustEmailCustNameProductCategoryCatDiscountQtyDate
P01jo@mail.comJoKeyboardPeripherals10%201/03/26
P02jo@mail.comJoMonitorDisplays5%102/03/26
P03sam@mail.comSamMousePeripherals10%303/03/26
Busca cadenas: ¿CatDiscount depende de Category, que depende de Product?
10
Difícil — Esta tabla de hotel tiene un grupo repetitivo. Normalízala a través de los tres pasos hasta 3NF.
ReservIDGuestGuestEmailCheckInRoomNoRoomTypeRateServices
R01Liamliam@mail.com01/03101Single€80Breakfast €15, Spa €40
R02Miamia@mail.com02/03205Double€120Breakfast €15, Gym €10, Laundry €25
R03Liamliam@mail.com10/03101Single€80Gym €10
Comienza con la columna Services — tiene múltiples valores. Luego busca qué describe al huésped vs. qué describe la habitación.
11
Desafío — Una universidad almacena inscripciones de estudiantes. Esta tabla tiene grupos repetitivos Y dependencias transitivas. Normaliza a 3NF mostrando cada paso.
StudentIDNameAddressDeptCodeDeptNameModules
S001AvaDublinCSComp SciM101 Databases (Dr Ryan, B+), M102 Networks (Dr Kelly, A)
S002NoahCorkCSComp SciM101 Databases (Dr Ryan, A-), M103 Web Dev (Dr Murphy, B)
S003EllaGalwayBABusinessM201 Marketing (Dr Walsh, A), M101 Databases (Dr Ryan, B+)
La columna Modules tiene código de módulo, nombre, profesor y calificación todos agrupados. Después de dividir, pregunta: ¿el nombre del módulo depende del estudiante o del código del módulo? ¿La calificación depende de una clave o de dos?
19
RESPUESTAS

Respuestas

01
Course_code, Course_name, Start_date, Weekly_time
Estos cuatro atributos se repiten para cada curso que imparte un profesor — forman el grupo repetitivo que viola la 1NF.
02
(Lecturer_no, Course_code)
Ninguno de los atributos por sí solo puede identificar una fila de forma única — Lecturer_no se repite para cada curso, y Course_code se repite si varios profesores imparten el mismo curso. Juntos son únicos.
03
Dependencia transitiva — viola la 3NF
Name, Address y Contact Number dependen de Customer Number, que es un atributo no clave. La solución es extraer una tabla CUSTOMER con Customer Number como PK, y mantener solo Customer Number como FK en ORDER.
04
2NF — dependencia parcial
PatientName depende solo de VisitID, no de la clave compuesta completa (VisitID + TreatmentName). La solución es mover los datos del paciente a una tabla Visits separada.
05
Una clave compuesta es dos o más atributos que juntos forman una clave primaria (ej. Order Number + Item Number en ORDER_ITEM). Una clave foránea es un atributo que referencia la clave primaria de otra tabla para crear una relación (ej. Customer Number en ORDER referencia CUSTOMER).
Una clave compuesta identifica filas dentro de su propia tabla; una clave foránea enlaza filas en otra tabla. Tienen propósitos diferentes — identificación vs. relación.
06
No está en 3NF. CategoryDesc depende de CategoryID (dependencia transitiva), no directamente de BookID. Solución: dividir en BOOK(BookID, BookDesc, CategoryID FK) y CATEGORY(CategoryID, CategoryDesc).
BookID → CategoryID → CategoryDesc es una cadena de dependencias. En 3NF, cada atributo no clave debe depender solo de la clave primaria, sin intermediarios.
07
Tabla Original
LoanIDMemberNameMemberEmailBookTitleAuthorLoanDateReturnDate
L01Jane Doejane@mail.comSQL BasicsT. Brown01/03/2615/03/26
L02Jane Doejane@mail.comData DesignR. Singh05/03/2619/03/26
L03Mark Leemark@mail.comSQL BasicsT. Brown10/03/2624/03/26
Paso 1 — 1NF: Verificar cada celda — ¿alguna contiene múltiples valores? No, cada celda tiene exactamente un valor. ✓ Ya está en 1NF.
⬇ La tabla se mantiene igual
Verificación paso 1 — tabla sin cambios
LoanIDMemberNameMemberEmailBookTitleAuthorLoanDateReturnDate
L01Jane Doejane@mail.comSQL BasicsT. Brown01/03/2615/03/26
L02Jane Doejane@mail.comData DesignR. Singh05/03/2619/03/26
L03Mark Leemark@mail.comSQL BasicsT. Brown10/03/2624/03/26
Paso 2 — 2NF: Is there a composite key? No — the clave primaria is LoanID (single column). Las dependencias parciales solo ocurren con claves compuestas. ✓ Ya está en 2NF.
⬇ La tabla se mantiene igual
Verificación paso 2 — tabla sin cambios
LoanIDMemberNameMemberEmailBookTitleAuthorLoanDateReturnDate
L01Jane Doejane@mail.comSQL BasicsT. Brown01/03/2615/03/26
L02Jane Doejane@mail.comData DesignR. Singh05/03/2619/03/26
L03Mark Leemark@mail.comSQL BasicsT. Brown10/03/2624/03/26
Paso 3 — 3NF: Para cada columna no clave, pregunta: "¿esto describe la PK o a otra columna?"
• MemberName y MemberEmail dependen del member, not on LoanID — dependencia transitiva.
• BookTitle y Author dependen del book, not on LoanID — dependencia transitiva.
Fix: extraer las tablas MEMBER y BOOK.
⬇ Resultado 3NF — tres tablas
MEMBER
MemberIDMemberNameMemberEmail
M01Jane Doejane@mail.com
M02Mark Leemark@mail.com
BOOK
BookIDBookTitleAuthor
B01SQL BasicsT. Brown
B02Data DesignR. Singh
LOAN
LoanIDMemberID (FK)BookID (FK)LoanDateReturnDate
L01M01B0101/03/2615/03/26
L02M01B0205/03/2619/03/26
L03M02B0110/03/2624/03/26
Resultado: 3 tablas en 3NF. Each fact stored once — changing Jane's email updates exactly one row in MEMBER.
Relaciones entre Tablas
1NN1MEMBERMemberIDPKMemberNameMemberEmailLOANLoanIDPKMemberIDFKBookIDFKLoanDateReturnDateBOOKBookIDPKBookTitleAuthor
08
Tabla Original
BookingIDClientPhoneClassInstructorInst PhoneRoomDate
B01Anna555-1234YogaCoach Kim555-9999R110/03/26
B02Tom555-5678YogaCoach Kim555-9999R110/03/26
B03Anna555-1234PilatesCoach Lee555-8888R211/03/26
Paso 1 — 1NF: Verificar cada celda — ¿alguna contiene múltiples valores? No, cada celda tiene exactamente un valor. ✓ Ya está en 1NF.
⬇ La tabla se mantiene igual
Verificación paso 1 — tabla sin cambios
BookingIDClientPhoneClassInstructorInst PhoneRoomDate
B01Anna555-1234YogaCoach Kim555-9999R110/03/26
B02Tom555-5678YogaCoach Kim555-9999R110/03/26
B03Anna555-1234PilatesCoach Lee555-8888R211/03/26
Paso 2 — 2NF: Is there a composite key? No — the clave primaria is BookingID (single column). Las dependencias parciales solo ocurren con claves compuestas. ✓ Ya está en 2NF.
⬇ La tabla se mantiene igual
Verificación paso 2 — tabla sin cambios
BookingIDClientPhoneClassInstructorInst PhoneRoomDate
B01Anna555-1234YogaCoach Kim555-9999R110/03/26
B02Tom555-5678YogaCoach Kim555-9999R110/03/26
B03Anna555-1234PilatesCoach Lee555-8888R211/03/26
Paso 3 — 3NF: Para cada columna no clave, pregunta: "¿esto describe la PK o a otra columna?"
• Phone depende de Client, not on BookingID — dependencia transitiva (Anna's phone repeats in B01 & B03).
• Instructor, Inst Phone & Room depend on Class, not on BookingID — dependencia transitiva (Yoga is always Coach Kim in R1).
• Inst Phone depende de Instructor, not on Class — another dependencia transitiva (Coach Kim's phone describes the instructor).
Fix: extraer las tablas CLIENT, INSTRUCTOR y CLASS.
⬇ Resultado 3NF — cuatro tablas
CLIENT
ClientIDClientNamePhone
C01Anna555-1234
C02Tom555-5678
INSTRUCTOR
InstructorIDNamePhone
I01Coach Kim555-9999
I02Coach Lee555-8888
CLASS
ClassIDClassNameInstructorID (FK)Room
CL01YogaI01R1
CL02PilatesI02R2
BOOKING
BookingIDClientID (FK)ClassID (FK)Date
B01C01CL0110/03/26
B02C02CL0110/03/26
B03C01CL0211/03/26
Resultado: 4 tablas en 3NF. Each fact stored once — changing Coach Kim's phone updates one row in INSTRUCTOR.
Relaciones entre Tablas
1NN1N1CLIENTClientIDPKClientNamePhoneBOOKINGBookingIDPKClientIDFKClassIDFKDateCLASSClassIDPKClassNameInstructorIDFKRoomINSTRUCTORInstructorIDPKNamePhone
09
Tabla Original
PurchIDCustEmailCustNameProductCategoryCatDiscountQtyDate
P01jo@mail.comJoKeyboardPeripherals10%201/03/26
P02jo@mail.comJoMonitorDisplays5%102/03/26
P03sam@mail.comSamMousePeripherals10%303/03/26
Paso 1 — 1NF: Verificar cada celda — ¿alguna contiene múltiples valores? No, cada celda tiene exactamente un valor. ✓ Ya está en 1NF.
⬇ La tabla se mantiene igual
Verificación paso 1 — tabla sin cambios
PurchIDCustEmailCustNameProductCategoryCatDiscountQtyDate
P01jo@mail.comJoKeyboardPeripherals10%201/03/26
P02jo@mail.comJoMonitorDisplays5%102/03/26
P03sam@mail.comSamMousePeripherals10%303/03/26
Paso 2 — 2NF: Is there a composite key? No — the clave primaria is PurchID (single column). Las dependencias parciales solo ocurren con claves compuestas. ✓ Ya está en 2NF.
⬇ La tabla se mantiene igual
Verificación paso 2 — tabla sin cambios
PurchIDCustEmailCustNameProductCategoryCatDiscountQtyDate
P01jo@mail.comJoKeyboardPeripherals10%201/03/26
P02jo@mail.comJoMonitorDisplays5%102/03/26
P03sam@mail.comSamMousePeripherals10%303/03/26
Paso 3 — 3NF: Para cada columna no clave, pregunta: "¿esto describe la PK o a otra columna?"
• CustName depende de CustEmail, not on PurchID — dependencia transitiva (Jo's name repeats whenever jo@mail.com appears).
• Category depende de Product, not on PurchID — dependencia transitiva (Keyboard is always Peripherals).
• CatDiscount depende de Category, not on Product — this is a cadena doble transitiva: PurchID → Product → Category → CatDiscount (el 10% pertenece a all Peripherals, no por producto).
Fix: extraer las tablas CUSTOMER, CATEGORY y PRODUCT.
⬇ Resultado 3NF — cuatro tablas
CUSTOMER
CustIDCustEmailCustName
C01jo@mail.comJo
C02sam@mail.comSam
CATEGORY
CatIDCatNameCatDiscount
CAT01Peripherals10%
CAT02Displays5%
PRODUCT
ProdIDProdNameCatID (FK)
PR01KeyboardCAT01
PR02MonitorCAT02
PR03MouseCAT01
PURCHASE
PurchIDCustID (FK)ProdID (FK)QtyDate
P01C01PR01201/03/26
P02C01PR02102/03/26
P03C02PR03303/03/26
Resultado: 4 tablas en 3NF. Each fact stored once — changing Peripherals discount from 10% to 15% updates one row in CATEGORY.
Relaciones entre Tablas
1NN1N1CUSTOMERCustIDPKCustEmailCustNamePURCHASEPurchIDPKCustIDFKProdIDFKQtyDatePRODUCTProdIDPKProdNameCatIDFKCATEGORYCatIDPKCatNameCatDiscount
10
Tabla Original
ReservIDGuestGuestEmailCheckInRoomNoRoomTypeRateServices
R01Liamliam@mail.com01/03101Single€80Breakfast €15, Spa €40
R02Miamia@mail.com02/03205Double€120Breakfast €15, Gym €10, Laundry €25
R03Liamliam@mail.com10/03101Single€80Gym €10
Paso 1 — 1NF: La columna Services tiene múltiples valores (Breakfast €15, Spa €40). Esto es un grupo repetitivo. Fix: mover los servicios a una nueva tabla RESERVATION_SERVICE con clave compuesta (ReservID + ServiceName).
⬇ Resultado 1NF
1NF — Todos los valores atómicos (uno por celda)
ReservIDGuestGuestEmailCheckInRoomNoRoomTypeRateServiceNameServicePrice
R01Liamliam@mail.com01/03101Single€80Breakfast€15
R01Liamliam@mail.com01/03101Single€80Spa€40
R02Miamia@mail.com02/03205Double€120Breakfast€15
R02Miamia@mail.com02/03205Double€120Gym€10
R02Miamia@mail.com02/03205Double€120Laundry€25
R03Liamliam@mail.com10/03101Single€80Gym€10
Observa la redundancia: Liam's details repeat for each service. Room 101's type and rate repeat. Breakfast's price (€15) appears twice. Next: dividir en RESERVATION + RESERVATION_SERVICE, linked by ReservID.
⬇ Dividir en separate tables
RESERVATION (después de 1NF)
ReservIDGuestGuestEmailCheckInRoomNoRoomTypeRate
R01Liamliam@mail.com01/03101Single€80
R02Miamia@mail.com02/03205Double€120
R03Liamliam@mail.com10/03101Single€80
RESERVATION_SERVICE (después de 1NF)
ReservIDServiceNamePrice
R01Breakfast€15
R01Spa€40
R02Breakfast€15
R02Gym€10
R02Laundry€25
R03Gym€10
Paso 2 — 2NF: RESERVATION_SERVICE has composite key (ReservID, ServiceName). Price depende dely on ServiceName (Breakfast is always €15) — dependencia parcial. Fix: extraer la tabla SERVICE.
⬇ Resultado 2NF
SERVICE
ServiceIDServiceNamePrice
SV01Breakfast€15
SV02Spa€40
SV03Gym€10
SV04Laundry€25
RESERVATION_SERVICE (después de 2NF)
ReservID (FK)ServiceID (FK)
R01SV01
R01SV02
R02SV01
R02SV03
R02SV04
R03SV03
Paso 3 — 3NF: En RESERVATION: Guest y GuestEmail dependen del huésped (no de ReservID) — transitiva. RoomType y Rate dependen de RoomNo (no de ReservID) — transitiva. Fix: extraer las tablas GUEST y ROOM.
⬇ Resultado 3NF — cinco tablas
GUEST
GuestIDGuestNameGuestEmail
G01Liamliam@mail.com
G02Miamia@mail.com
ROOM
RoomNoRoomTypeRate
101Single€80
205Double€120
RESERVATION
ReservIDGuestID (FK)RoomNo (FK)CheckIn
R01G0110101/03
R02G0220502/03
R03G0110110/03
RESERVATION_SERVICE
ReservID (FK)ServiceID (FK)
R01SV01
R01SV02
R02SV01
R02SV03
R02SV04
R03SV03
Resultado: 5 tablas en 3NF. All three steps used: 1NF (grupo repetitivo), 2NF (dependencia parcial), 3NF (two transitive chains). Each fact stored once.
Relaciones entre Tablas
1NN11NN1GUESTGuestIDPKGuestNameGuestEmailRESERVATIONReservIDPKGuestIDFKRoomNoFKCheckInROOMRoomNoPKRoomTypeRateRESERV_SERVICEReservIDFKServiceIDFKSERVICEServiceIDPKServiceNamePrice
11
Tabla Original
StudentIDNameAddressDeptCodeDeptNameModules
S001AvaDublinCSComp SciM101 Databases (Dr Ryan, B+), M102 Networks (Dr Kelly, A)
S002NoahCorkCSComp SciM101 Databases (Dr Ryan, A-), M103 Web Dev (Dr Murphy, B)
S003EllaGalwayBABusinessM201 Marketing (Dr Walsh, A), M101 Databases (Dr Ryan, B+)
Paso 1 — 1NF: La columna Modules agrupa múltiples valores (código, nombre, profesor, calificación por módulo). Grupo repetitivo encontrado. Fix: create ENROLMENT table. Clave compuesta = (StudentID + ModCode).
⬇ Resultado 1NF
1NF — Todos los valores atómicos (uno por celda)
StudentIDNameAddressDeptCodeDeptNameModCodeModNameLecturerGrade
S001AvaDublinCSComp SciM101DatabasesDr RyanB+
S001AvaDublinCSComp SciM102NetworksDr KellyA
S002NoahCorkCSComp SciM101DatabasesDr RyanA-
S002NoahCorkCSComp SciM103Web DevDr MurphyB
S003EllaGalwayBABusinessM201MarketingDr WalshA
S003EllaGalwayBABusinessM101DatabasesDr RyanB+
Observa la redundancia: Ava's details repeat for each module. DeptName 'Comp Sci' repeats for every CS student. Module M101 'Databases' and 'Dr Ryan' repeat for each student enrolled. Next: dividir en STUDENT + ENROLMENT, linked by StudentID.
⬇ Dividir en separate tables
STUDENT (después de 1NF)
StudentIDNameAddressDeptCodeDeptName
S001AvaDublinCSComp Sci
S002NoahCorkCSComp Sci
S003EllaGalwayBABusiness
ENROLMENT (después de 1NF)
StudentIDModCodeModNameLecturerGrade
S001M101DatabasesDr RyanB+
S001M102NetworksDr KellyA
S002M101DatabasesDr RyanA-
S002M103Web DevDr MurphyB
S003M201MarketingDr WalshA
S003M101DatabasesDr RyanB+
Paso 2 — 2NF: Clave compuesta (StudentID + ModCode). Pregunta: ¿ModName necesita ambas claves? No — M101 siempre es "Databases" independientemente del estudiante. Lo mismo para Lecturer. Dependencia parcial. Fix: extract MODULE table. ENROLMENT keeps only Grade (depende de both keys).
⬇ Resultado 2NF
MODULE
ModCodeModNameLecturer
M101DatabasesDr Ryan
M102NetworksDr Kelly
M103Web DevDr Murphy
M201MarketingDr Walsh
ENROLMENT (después de 2NF)
StudentID (FK)ModCode (FK)Grade
S001M101B+
S001M102A
S002M101A-
S002M103B
S003M201A
S003M101B+
Paso 3 — 3NF: In STUDENT: DeptName depende de DeptCode (not StudentID) — dependencia transitiva. CS siempre es "Comp Sci". Fix: extraer la tabla DEPARTMENT.
⬇ Resultado 3NF — cuatro tablas
DEPARTMENT
DeptCodeDeptName
CSComp Sci
BABusiness
STUDENT
StudentIDNameAddressDeptCode (FK)
S001AvaDublinCS
S002NoahCorkCS
S003EllaGalwayBA
MODULE
ModCodeModNameLecturer
M101DatabasesDr Ryan
M102NetworksDr Kelly
M103Web DevDr Murphy
M201MarketingDr Walsh
ENROLMENT
StudentID (FK)ModCode (FK)Grade
S001M101B+
S001M102A
S002M101A-
S002M103B
S003M201A
S003M101B+
Resultado: 4 tablas en 3NF. All three steps used: 1NF (repeating modules), 2NF (partial dep on ModCode), 3NF (transitive dep on DeptCode). Grade is the only attribute that genuinely needs both parts of the composite key.
Relaciones entre Tablas
1N1NN1DEPARTMENTDeptCodePKDeptNameSTUDENTStudentIDPKNameAddressDeptCodeFKENROLMENTStudentIDFKModCodeFKGradeMODULEModCodePKModNameLecturer
20
REFERENCIAS

Referencias

Fuentes utilizadas en la elaboración de este material

01
Database Normalization: 1NF, 2NF, 3NF & BCNF Examples
Tutorial completo con ejemplos visuales para cada forma normal
Consultado en: Consultado el 22 de marzo de 2026
02
Database Normalization – Normal Forms 1nf 2nf 3nf Table Examples
Guía paso a paso de normalización con ejemplos prácticos de tablas
Consultado en: Consultado el 22 de marzo de 2026
03
Normal Forms in DBMS
Guía de referencia que cubre todas las formas normales con definiciones y ejemplos
Consultado en: Consultado el 22 de marzo de 2026
04
DBMS Normalization: 1NF, 2NF, 3NF Database Example
Tutorial de normalización para principiantes con diagramas y ejemplos SQL
Consultado en: Consultado el 22 de marzo de 2026