Diseñar una base de datos son cinco pasos en orden: describir en prosa qué hace el sistema, identificar las entidades (los sustantivos que se repiten y tienen características propias), listar sus atributos, definir las relaciones entre ellas, y normalizar hasta que cada dato viva en un solo lugar. La normalización llega hasta la tercera forma normal en la enorme mayoría de los proyectos, y se resume en una regla: cada columna que no es clave depende «de la clave, de toda la clave y de nada más que la clave».
Ver índice de contenidos
El caso que vamos a diseñar
Diseñar en abstracto no se aprende, así que vamos con un caso concreto y lo llevamos hasta el final. La descripción, tal como podría salir de una conversación con quien va a usar el sistema:
«Necesito registrar los pedidos de mis clientes. Cada cliente tiene nombre, correo y la ciudad donde vive. Un pedido lo hace un cliente en una fecha, y puede incluir varios productos, cada uno con su cantidad. Los productos tienen nombre y precio, y el precio cambia con el tiempo, pero la factura vieja tiene que seguir mostrando lo que se pagó.»
Esa última frase es la más importante de todas, y es el tipo de detalle que solo aparece si preguntás. Vamos a ver por qué condiciona el diseño entero.
Paso 1: encontrar las entidades
La técnica es mecánica y funciona sorprendentemente bien: subrayá los sustantivos de la descripción y quedate con los que se repiten y tienen características propias.
En nuestro caso salen tres claros: cliente, pedido y producto. Cada uno es un tipo de cosa distinto, con datos propios, y existe independientemente de los otros: un producto sigue siendo un producto aunque nadie lo haya comprado.
Los verbos que conectan dos sustantivos son las relaciones: un cliente hace pedidos, un pedido incluye productos.
«Ciudad» aparece en la descripción, ¿es una entidad o un atributo del cliente? La pregunta que decide es: ¿necesito guardar datos sobre la ciudad? Si solo necesito el nombre para mostrarlo, es un atributo. Si necesito su provincia, su código postal o su zona de reparto, es una entidad. Empezá con el atributo: partirlo después es fácil, y adelantarse llena el esquema de tablas que nadie usa.
Paso 2: atributos y tipos
Para cada entidad, qué datos guardamos y de qué tipo. Acá es donde se paga o se ahorra trabajo futuro.
| Entidad | Atributos y tipos |
|---|---|
| cliente | id INT · nombre VARCHAR(80) NOT NULL · correo VARCHAR(120) UNIQUE · ciudad VARCHAR(80) · alta DATE |
| pedido | id INT · cliente_id INT NOT NULL · fecha DATE NOT NULL · estado VARCHAR(20) |
| producto | id INT · nombre VARCHAR(120) NOT NULL · precio DECIMAL(10,2) NOT NULL |
Tres decisiones de esa tabla que no son obvias. El id numérico en las tres es una clave subrogada: no significa nada, y por eso nunca hay que cambiarlo. El precio va en DECIMAL y no en un tipo de punto flotante, porque el punto flotante introduce errores de redondeo que aparecen al sumar. Y la fecha va en DATE, no en texto, porque en texto se pierde poder comparar y calcular.
Fijate en qué no está: el total del pedido. Es un dato calculable a partir de sus productos, y guardar algo que se puede calcular es abrir la puerta a que la copia y el cálculo no coincidan. Hay una excepción legítima, y la vemos en la sección de desnormalización.
Paso 3: definir las relaciones
Para cada par de entidades conectadas, la pregunta se hace en las dos direcciones. Es la única forma de no equivocarse.
- Cliente y pedido. ¿Un cliente cuántos pedidos tiene? Varios. ¿Un pedido de cuántos clientes es? De uno. Entonces es uno a muchos, y la clave foránea va en el lado «muchos»:
pedidos.cliente_id. - Pedido y producto. ¿Un pedido cuántos productos lleva? Varios. ¿Un producto en cuántos pedidos aparece? En varios. Entonces es muchos a muchos, y hace falta una tabla intermedia.
Y acá vuelve la frase clave del pedido original: «la factura vieja tiene que seguir mostrando lo que se pagó». Si el precio vive solo en productos y mañana lo actualizás, todas las facturas históricas cambian de monto. La solución es guardar el precio del momento de la compra en la tabla intermedia. No es duplicación: es un dato distinto —lo que se pagó— que casualmente coincide con el precio actual el día de la venta.
Paso 4: normalizar
Normalizar es reorganizar las tablas para que cada dato viva en un solo lugar. Se hace por etapas llamadas formas normales, y cada una elimina un tipo concreto de repetición. Suele explicarse con definiciones abstractas que no se entienden; con tablas concretas se vuelve evidente.
Primera forma normal: un valor por celda
El punto de partida tiene una columna productos con «Teclado, Mouse, Monitor» adentro. Eso rompe la regla más básica: cada celda contiene un solo valor. Mientras esté así no se puede consultar por producto, ni sumar por producto, ni relacionarlo con la tabla de productos.
La solución es abrir el grupo: una fila por cada producto del pedido. Se gana la capacidad de consultar, y se paga con que ahora se repite todo lo demás en cada fila.
Segunda forma normal: nada que dependa de parte de la clave
Con la clave compuesta por pedido y producto, aparece el problema: el precio depende solo del producto, no del pedido. Está repetido en cada fila donde aparece ese producto, así que si hay que corregirlo hay que corregirlo en muchos lugares.
La solución es sacar el producto y su precio a su propia tabla, y dejar en la intermedia solo lo que depende de la combinación: la cantidad y el precio pagado.
Tercera forma normal: nada que dependa de otra columna no clave
Queda un caso más sutil. En la tabla de pedidos están el nombre del cliente y su ciudad, pero la ciudad no depende del pedido: depende del cliente. Eso se llama dependencia transitiva, y su consecuencia práctica es que si un cliente se muda, hay que actualizar todos sus pedidos.
La solución es sacar el cliente y sus datos a la tabla clientes, y dejar en pedidos solo la referencia.
Cada columna que no es clave tiene que depender «de la clave, de toda la clave y de nada más que la clave». «De la clave» es primera forma normal, «de toda la clave» es la segunda, «de nada más que la clave» es la tercera. Con eso llegás a 3.ª forma normal, y para la enorme mayoría de los proyectos ahí alcanza.
Paso 5: el esquema final
El diseño completo, escrito en SQL. Notá que las restricciones no son decoración: son las reglas que hacen que la base se cuide sola.
CREATE TABLE clientes (
id INT PRIMARY KEY AUTO_INCREMENT,
nombre VARCHAR(80) NOT NULL,
correo VARCHAR(120) NOT NULL UNIQUE,
ciudad VARCHAR(80),
alta DATE NOT NULL DEFAULT (CURRENT_DATE),
activo BOOLEAN NOT NULL DEFAULT TRUE
);
CREATE TABLE productos (
id INT PRIMARY KEY AUTO_INCREMENT,
nombre VARCHAR(120) NOT NULL,
precio DECIMAL(10,2) NOT NULL,
CHECK (precio >= 0)
);
CREATE TABLE pedidos (
id INT PRIMARY KEY AUTO_INCREMENT,
cliente_id INT NOT NULL,
fecha DATE NOT NULL,
estado VARCHAR(20) NOT NULL DEFAULT 'nuevo',
FOREIGN KEY (cliente_id) REFERENCES clientes(id)
);
CREATE TABLE pedido_producto (
pedido_id INT NOT NULL,
producto_id INT NOT NULL,
cantidad INT NOT NULL,
precio_pagado DECIMAL(10,2) NOT NULL, -- el del día de la compra
PRIMARY KEY (pedido_id, producto_id),
FOREIGN KEY (pedido_id) REFERENCES pedidos(id),
FOREIGN KEY (producto_id) REFERENCES productos(id),
CHECK (cantidad > 0)
);
Cuatro tablas para un sistema completo de pedidos. La clave primaria compuesta de la intermedia impide cargar dos veces el mismo producto en el mismo pedido, y los CHECK impiden precios negativos y cantidades en cero.
Cuándo conviene no normalizar
Desnormalizar es repetir datos a propósito, y no es un pecado: es una decisión de ingeniería con un costo conocido. El caso típico es un informe que se consulta mil veces por día y cuyos datos cambian una vez por mes: recalcular el total de cada pedido en cada consulta es trabajo desperdiciado.
Lo que separa una desnormalización sana de un problema son tres condiciones:
- Que sea consciente y documentadaEscrito en el repositorio: qué está duplicado, por qué, y quién mantiene la copia sincronizada.
- Que llegue después de medirPrimero diseñás normalizado y medís. Desnormalizar antes de tener el problema es optimizar a ciegas.
- Que tenga un mecanismo de sincronizaciónSi guardás el total del pedido, algo tiene que actualizarlo cuando cambian sus líneas. Si ese algo es «me acuerdo de hacerlo», va a fallar.
Y hay un caso que parece desnormalización y no lo es: el precio_pagado de nuestro esquema. No es una copia del precio del producto; es un dato distinto —el importe de esa transacción— que resulta igual el día de la venta. Guardarlo no repite información: la preserva.
Tres decisiones que siempre aparecen
No están en los manuales de normalización y aparecen en todos los proyectos reales.
¿Borrar o marcar como inactivo? Un cliente que se va no se puede borrar: sus pedidos pasados lo referencian y perderías el historial. Se marca con una columna activo o una fecha de baja, que es lo que hace nuestro esquema. La pregunta que resuelve el caso: si borro esto, ¿queda algo huérfano o pierdo información que alguien puede necesitar?
¿Cuándo guardar fecha de creación y modificación? Casi siempre, y desde el principio. Son dos columnas que casi no cuestan y que responden preguntas que van a aparecer: cuándo se cargó esto, qué se modificó esta semana, en qué orden se dieron de alta. Agregarlas después significa tener esos datos vacíos para todo lo que ya existe.
¿Qué hacer con los datos personales? Esta merece pensarse en la etapa de diseño, no después. La regla más efectiva es no guardar lo que no vas a usar: lo que no está en la base no se puede filtrar. Si el sistema no necesita la fecha de nacimiento, no la pidas. Y para los datos que sí hacen falta, el diseño debería contemplar desde el inicio quién puede leerlos —con usuarios y permisos separados— y qué se hace cuando alguien pide que borren los suyos.
Errores frecuentes al diseñar
- Empezar por las tablas en lugar de por la descripción. Sin entender el dominio, el esquema modela lo que uno supone y no lo que hace falta.
- Columnas numeradas.
producto_1,producto_2,producto_3es siempre una relación uno a muchos disfrazada, y se rompe con el cuarto. - Varios valores separados por coma. Rompe la primera forma normal y hace imposible consultar por esos valores.
- Guardar lo que se puede calcular. Un total guardado se desincroniza del cálculo, salvo que haya un mecanismo explícito que lo mantenga.
- Guardar el precio actual en lugar del pagado. Las facturas históricas cambian de monto cuando actualizás la lista de precios.
- Usar un dato de negocio como clave primaria. El día que hay que corregirlo, el cambio se propaga a todas las tablas.
- Crear tablas para atributos simples. Una tabla de dos columnas que solo guarda un nombre suele ser un atributo que se separó de más.
- Diseñar directamente en el editor de SQL. Cuesta ver el conjunto y las relaciones. Un dibujo, aunque sea a mano, detecta la mitad de los problemas antes.
- Pedir datos personales «por si acaso». Es el error más difícil de revertir: lo que no guardás no se puede filtrar.
Preguntas frecuentes
¿Qué es normalizar una base de datos?
Es reorganizar las tablas para que cada dato viva en un solo lugar, eliminando la repetición que permite que la base se contradiga. Se hace por etapas llamadas formas normales, y cada una elimina un tipo concreto de repetición: la primera saca los grupos de valores dentro de una celda, la segunda separa lo que depende solo de parte de una clave compuesta, y la tercera saca lo que depende de una columna que no es clave. Para la enorme mayoría de los proyectos, llegar a la tercera forma normal alcanza.
¿Cómo identifico las entidades de mi sistema?
Escribí en prosa qué hace el sistema y subrayá los sustantivos que se repiten. Los que aparecen varias veces y tienen características propias suelen ser entidades, y por lo tanto tablas: cliente, pedido, producto, sucursal. Los verbos que conectan dos sustantivos suelen ser relaciones. Y un sustantivo que solo describe a otro —el color de un producto, la ciudad de un cliente— probablemente sea un atributo y no una tabla, aunque eso puede cambiar si después necesitás datos propios sobre él.
¿Está mal desnormalizar?
No si es una decisión consciente y documentada. Desnormalizar es repetir datos a propósito para acelerar lecturas, y tiene sentido en informes o tableros que consultan mucho y escriben poco. Lo que está mal es desnormalizar sin darse cuenta, o hacerlo antes de tener un problema medido de rendimiento. El orden correcto es diseñar normalizado, medir, y desnormalizar solo el punto concreto que lo justifique, dejando escrito por qué y quién mantiene sincronizada la copia.
¿Cuántas tablas debería tener una base sencilla?
Menos de las que uno teme y más de las que uno quiere. Un sistema de pedidos completo se modela cómodamente con cuatro o cinco tablas: clientes, pedidos, productos y la intermedia entre pedidos y productos. Si te salen veinte tablas para algo chico, probablemente estés separando cosas que son atributos. Si te sale una sola tabla con veinticinco columnas, seguro falta separar. La cantidad correcta la determina cuántos tipos de cosa distintos hay, no la ambición del diseño.
¿Conviene borrar registros o marcarlos como inactivos?
Depende de si el dato tiene historia. Un cliente que se va no se borra: sus pedidos pasados tienen que seguir existiendo y referenciándolo, así que se marca como inactivo con una columna de estado o una fecha de baja. Un registro cargado por error sí se borra. La pregunta que resuelve el caso es: si borro esto, ¿queda algo huérfano o pierdo información que alguien puede necesitar? Si la respuesta es sí, corresponde marcar en lugar de borrar.
¿Hace falta dibujar un diagrama entidad-relación?
Hace falta pensar el modelo; el diagrama es la herramienta más cómoda para hacerlo y para discutirlo con otras personas. No necesita ser formal ni hecho con una herramienta especial: cajas con el nombre de la tabla, sus columnas, y líneas con la cardinalidad alcanza para detectar la mitad de los problemas antes de escribir una sola instrucción SQL. Lo que no conviene es diseñar directamente en el editor de SQL, porque ahí es difícil ver el conjunto.
Fuentes
Documentación oficial y referencias consultadas para esta guía. Fecha de consulta: 27 de julio de 2026.
- PostgreSQL. Constraints. Restricciones disponibles y por qué los tipos de dato solos no alcanzan para garantizar la integridad.
- PostgreSQL. Data Types. Tipos disponibles, incluidos los numéricos exactos para valores monetarios.
- PostgreSQL. Data Definition. Creación de tablas, claves y relaciones.
- Codd, E. F. «A Relational Model of Data for Large Shared Data Banks». Communications of the ACM, vol. 13, n.º 6, 1970, pp. 377-387. Artículo original del modelo relacional, donde se introducen las primeras formas normales. Publicación con acceso restringido; se cita como referencia bibliográfica.
- Underc0de, foro. Sección Base de Datos. Material de la comunidad sobre modelado y SQL.