Un diagrama ER es donde se revisa el diseño de una base de datos antes de que se convierta en migraciones. Una lista de tablas te dice qué existe. El diagrama muestra cómo dependen las tablas entre sí: qué fila necesita a cuál, qué puede faltar y dónde se esconde una relación muchos a muchos.
Esta guía diseña la base de datos de una tienda online pequeña, desde requisitos en lenguaje sencillo hasta un diagrama entidad-relación terminado, y explica la notación a medida que aparece. La tienda es solo el ejemplo; el método sirve para cualquier esquema.
Cuándo necesitas un diagrama ER
Una lista de tablas basta cuando un esquema tiene un puñado de tablas y un solo equipo trabaja en él. Dibuja el diagrama cuando personas de fuera de ese equipo necesiten entender los datos, cuando revises un diseño antes de escribir migraciones o cuando un esquema haya crecido tanto que ya nadie lo tenga en la cabeza.
Hay dos notaciones habituales. La notación de Chen, del artículo de Peter Chen de 1976 que presentó el modelo entidad-relación, dibuja las entidades como rectángulos y las relaciones como rombos. Encaja con el modelado conceptual. La notación pata de gallo (crow's foot) dibuja las tablas como cajas y coloca la cardinalidad en los extremos de las líneas. Se suele atribuir a Gordon Everest, en 1976, y es la notación que usan la mayoría de las herramientas de diseño de bases de datos. Esta guía usa pata de gallo.
Paso 1: requisitos en frases sencillas
Escribe primero las reglas como frases. Cada una se convierte en una tabla, una columna o una línea.
- Un cliente se registra con una dirección de correo y puede guardar varias direcciones.
- Un cliente hace pedidos. Cada pedido se envía a una de las direcciones del cliente.
- Un pedido contiene uno o más productos, cada uno con una cantidad y el precio pagado.
- Cada producto pertenece a una categoría.
- Un pedido puede tener varios intentos de pago, y la mayoría tiene uno que salió bien.
Paso 2: entidades y claves
Los sustantivos se convierten en entidades: clientes, direcciones, pedidos, líneas de pedido, productos, categorías y pagos. Cada una recibe una clave primaria. Usa claves sustitutas (una columna de identidad) en la mayoría de las tablas, y claves naturales únicas donde el negocio ya tenga una: el correo de un cliente, el SKU de un producto.
Las líneas de pedido son la excepción. Una línea de pedido no tiene identidad propia; es el vínculo entre un pedido y un producto. Su clave primaria es el par (order_id, product_id).
Paso 3: relaciones y cardinalidad
Cada clave foránea es una línea. Los símbolos de cada extremo dicen cuántas filas pueden quedar de ese lado:
| Extremo de la línea | Se lee | Ejemplo de la tienda |
|---|---|---|
| Dos barras | Exactamente uno | Cada pedido lo hace exactamente un cliente |
| Círculo y barra | Cero o uno | Un pedido tiene cero o un mensaje de regalo, si añades uno |
| Barra y pata de gallo | Uno o muchos | Un pedido tiene una o muchas líneas de pedido |
| Círculo y pata de gallo | Cero o muchos | Un cliente tiene cero o muchos pedidos |
Lee una relación desde una tabla, a lo largo de la línea, hasta el símbolo del otro extremo: "un cliente hace cero o muchos pedidos", y de vuelta: "cada pedido lo hace exactamente un cliente".
Una clave foránea NOT NULL significa "exactamente uno" en el lado referenciado; una que admite NULL significa "cero o uno". El "uno o muchos" del otro lado es una regla de negocio, no algo que imponga una clave foránea, así que escríbela en el diagrama, donde los lectores la vean.
Paso 4: el muchos a muchos
Pedidos y productos tienen una relación muchos a muchos: un pedido contiene muchos productos y un producto aparece en muchos pedidos. Las bases de datos relacionales lo modelan con una tabla en medio. Aquí esa tabla ya existe por una razón mejor que la pura fontanería: order_items guarda la cantidad y el precio unitario en el momento de la compra, datos que pertenecen al par y a ninguno de los dos lados por separado.
Paso 5: decisiones que conviene anotar
Algunas decisiones no se ven en la lista de columnas y causan bugs cuando nadie las conoce:
- Foto del precio.
order_items.unit_pricecopia el precio del producto en el momento de la compra. Cambiar un precio después no debe cambiar los pedidos antiguos. - Las direcciones no se editan en el sitio. En cuanto un pedido apunta a una dirección, editar esa fila reescribiría adónde fueron los pedidos pasados. Una edición crea una fila de dirección nueva.
- Los pagos son intentos. Una fila por intento, con un estado, para que los pagos fallidos y reintentados sigan visibles.
- El dinero es
numeric. La documentación de PostgreSQL recomiendanumericpara importes monetarios porque es exacto.
Paso 6: el DDL
Las dos tablas centrales en PostgreSQL:
CREATE TABLE orders (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
customer_id bigint NOT NULL REFERENCES customers (id),
shipping_address_id bigint NOT NULL REFERENCES addresses (id),
status text NOT NULL DEFAULT 'pending'
CHECK (status IN ('pending', 'paid', 'shipped', 'cancelled')),
currency char(3) NOT NULL,
total numeric(12,2) NOT NULL CHECK (total >= 0),
placed_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE order_items (
order_id bigint NOT NULL REFERENCES orders (id) ON DELETE CASCADE,
product_id bigint NOT NULL REFERENCES products (id),
quantity integer NOT NULL CHECK (quantity > 0),
unit_price numeric(12,2) NOT NULL, -- copied from products.price at checkout
PRIMARY KEY (order_id, product_id)
);
CREATE INDEX ON orders (customer_id);
CREATE INDEX ON order_items (product_id);
PostgreSQL no crea por sí solo un índice para una columna de clave foránea, así que las dos líneas CREATE INDEX importan para los joins y para los borrados en las tablas referenciadas. order_items.order_id queda cubierta por la clave primaria, cuyo índice empieza por esa columna. ON DELETE CASCADE dice que una línea de pedido no puede sobrevivir a su pedido.
El diagrama
Contenido del diagrama
- customers
- orders
- payments
- addresses
- order_items
- products
- categories
- belongs to
- placed by
- ships to
- pays for
- line of
- for
- in
Cómo leerlo:
- Los clientes (arriba a la izquierda) tienen cero o muchas direcciones y hacen cero o muchos pedidos.
- Los pedidos (en el centro) se envían a exactamente una dirección, contienen una o muchas líneas de pedido y tienen cero o muchos pagos.
- Las líneas de pedido enlazan cada pedido con productos, y cada producto pertenece a exactamente una categoría.
- La nota recoge las decisiones del paso 5, junto a las tablas a las que afectan.
Cómo dibujar un diagrama ER legible
- Nombra las relaciones con verbos. "hecho por", "se envía a", "paga" convierten las líneas en frases.
- Marca las claves en los atributos. Los marcadores PK y FK muestran de un vistazo a qué columna pertenece una línea.
- Agrupa las tablas por dominio. Clientes y direcciones, pedidos y pagos, el catálogo. Mantén cada grupo junto para que las líneas sean cortas.
- Deja fuera el ruido. Las columnas de auditoría como
created_byyupdated_at, los indicadores de borrado lógico en cada tabla y las tablas técnicas añaden filas sin añadir comprensión. - Dibuja la tabla muchos a muchos. Esconderla detrás de una línea directa entre pedidos y productos esconde también la cantidad y la foto del precio.
- Muestra las reglas de negocio que el esquema no puede expresar. "Una o muchas" líneas por pedido y "las direcciones no se editan" son reglas que todo el mundo debe conocer.
Mantenlo sincronizado con el esquema
Un diagrama ER dibujado a mano queda desactualizado tras la siguiente migración. Genera mejor un primer borrador a partir del esquema. La herramienta gratuita SQL a diagrama ER lee sentencias CREATE TABLE o un pg_dump completo y dibuja una tarjeta por tabla, con marcadores PK, FK y UK y una línea por clave foránea; también hay herramientas para PostgreSQL, Prisma y DBML. Los extremos pata de gallo generados siguen a las columnas: una clave foránea NOT NULL es obligatoria y una que admite NULL, opcional. Las reglas que el SQL no contiene, como "una o muchas" líneas, las añades a mano.
Constrúyelo en Archboard
- Inicia sesión con Google o GitHub y crea un diagrama.
- Para empezar desde el esquema, pega las sentencias CREATE TABLE en la herramienta SQL a diagrama ER y selecciona Abrir en Archboard. Para dibujar a mano, añade una Entidad del pack Entidad-relación por cada tabla, con un atributo por línea y marcadores PK y FK.
- Conecta cada clave foránea con la tabla a la que referencia y pon en los extremos de las líneas marcadores pata de gallo: exactamente uno en la tabla referenciada, cero o muchos en el lado de la clave foránea y uno o muchos donde lo diga una regla de negocio.
- Etiqueta cada línea con un verbo, como "hecho por" o "se envía a".
- Añade un bloque Markdown del pack Básico con las decisiones de diseño.
El ejemplo usa 8 nodos de diagrama, dentro del plan Free. Para ver cómo encaja un esquema en el resto de un sistema, consulta el ejemplo de diagrama de diseño de sistemas.
Preguntas frecuentes
¿Qué diferencia hay entre un diagrama ER y un diagrama de esquema de base de datos? En la práctica se solapan. Un diagrama ER puede ser conceptual y mostrar entidades y relaciones antes de que existan las tablas; un diagrama de esquema muestra las tablas, columnas y claves reales. El diagrama pata de gallo de esta guía es las dos cosas.
¿Debe tener cada tabla una clave sustituta?
La mayoría de las tablas sale ganando, porque las claves naturales cambian. Las tablas de enlace como order_items suelen usar en su lugar el par de claves foráneas como clave primaria.
¿Cómo muestro una relación muchos a muchos? Con la tabla del medio y dos líneas uno a muchos. Nombra la tabla del medio por lo que representa, como líneas de pedido, no por las dos tablas que une.
¿Dibujo todas las columnas? Dibuja las claves y las columnas que explican el diseño. Deja fuera las columnas de auditoría y las técnicas, salvo que el diagrama trate de ellas.
¿Chen o pata de gallo? Chen para conversaciones conceptuales con personas que no piensan en tablas; pata de gallo para todo lo que vaya a convertirse en una base de datos.