Ahora ha llegado el momento de mejorar nuestras skills y crear una de las relaciones más frecuentes en bases de datos relacionales — la relación ONE-TO-MANY.
Imagina una pequeña empresa. Un empleado solo puede trabajar en un departamento, pero en un departamento pueden currar decenas de empleados así. Tenemos dos objetos del mundo real: empleados y departamentos. La relación entre ellos se puede describir como "un departamento puede incluir a muchos empleados", o formalmente "uno a muchos" (ONE-TO-MANY).
Igualito, las relaciones ONE-TO-MANY están por todas partes:
- un cliente puede hacer muchos pedidos;
- un autor puede escribir un montón de libros;
- un profe puede enseñar a varios estudiantes.
En una base de datos relacional, la relación ONE-TO-MANY se implementa usando una clave foránea (FOREIGN KEY). Una de las columnas de la tabla "muchos" (MANY) apunta a la clave primaria de la tabla "uno" (ONE).
Cómo crear una relación ONE-TO-MANY
Vamos a ver el ejemplo clásico: la relación entre clientes y pedidos. Un cliente puede hacer muchos pedidos, pero cada pedido está vinculado solo a un cliente. Vamos a crear dos tablas: customers (clientes) y orders (pedidos).
Tabla customers
Esta es nuestra tabla "uno". Aquí vamos a guardar info sobre los clientes.
CREATE TABLE customers (
customer_id SERIAL PRIMARY KEY, -- Identificador único del cliente
name TEXT NOT NULL -- Nombre del cliente
);
Tabla orders
Esta es la tabla "muchos". Aquí se guardan los pedidos, donde cada pedido tiene una clave foránea customer_id que apunta al customer_id de la tabla customers.
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY, -- Identificador único del pedido
order_date DATE NOT NULL, -- Fecha del pedido
customer_id INT REFERENCES customers(customer_id) -- Clave foránea
);
Uso práctico
Insertando datos
Ahora vamos a meter algunos datos en nuestras tablas para comprobar que la relación funciona.
Agregamos clientes a la tabla customers:
INSERT INTO customers (name)
VALUES
('Ada Lovelace'),
('Grace Hopper'),
('Linus Torvalds');
Resultado:
| customer_id | name |
|---|---|
| 1 | Ada Lovelace |
| 2 | Grace Hopper |
| 3 | Linus Torvalds |
Agregamos pedidos a la tabla orders:
INSERT INTO orders (order_date, customer_id)
VALUES
('2023-10-01', 1), -- Pedido de Ada
('2023-10-02', 2), -- Pedido de Grace
('2023-10-03', 1); -- Otro pedido de Ada
Tabla orders:
| order_id | order_date | customer_id |
|---|---|---|
| 1 | 2023-10-01 | 1 |
| 2 | 2023-10-02 | 2 |
| 3 | 2023-10-03 | 1 |
Ojo: cuando añades un pedido tienes que poner sí o sí un customer_id que exista. Si intentas poner un ID que no existe, la base de datos te va a tirar un error. Así se protege la integridad de los datos.
Comprobando la relación
Ahora vamos a ver cómo están conectadas nuestras tablas. Por ejemplo, ¿qué pedidos hizo Ada Lovelace?
SELECT orders.order_id, orders.order_date, customers.name
FROM orders
JOIN customers ON orders.customer_id = customers.customer_id
WHERE customers.name = 'Ada Lovelace';
Resultado:
| order_id | order_date | name |
|---|---|---|
| 1 | 2023-10-01 | Ada Lovelace |
| 3 | 2023-10-03 | Ada Lovelace |
Aquí usamos el comando JOIN para juntar las dos tablas usando la clave foránea. Cómodo, limpio — ¡y sin datos duplicados!
¿Para qué sirve esto?
La relación ONE-TO-MANY es súper común y útil en la vida real. Imagina una tienda online con miles de clientes y millones de pedidos. En vez de duplicar la info del cliente en cada pedido, guardamos los clientes únicos en una tabla y los pedidos en otra. Así ahorramos espacio y la base queda mucho más ordenada.
Además, poder conectar datos te permite hacer consultas potentes para análisis. Por ejemplo, puedes preguntar: "¿Cuántos pedidos hizo cada cliente?" o "¿Qué clientes hicieron pedidos el último mes?".
Dificultades y trampas típicas
Esto es donde la peña que empieza suele tropezar:
Falta de clave foránea. Si te olvidas de poner la clave foránea en la tabla "muchos", la relación solo existe en tu cabeza, pero la base de datos no puede aplicarla de verdad. Eso significa que te arriesgas a tener una base "rota", donde hay pedidos que apuntan a clientes que no existen.
Intentar borrar un registro de la tabla "uno". Por ejemplo, si borras un cliente de customers, sus pedidos en orders se quedan "colgados". Para evitarlo, puedes usar ON DELETE CASCADE, así cuando borres un cliente, se borran automáticamente sus pedidos.
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
order_date DATE NOT NULL,
customer_id INT REFERENCES customers(customer_id) ON DELETE CASCADE
);
Ahora, si borras un cliente:
DELETE FROM customers WHERE customer_id = 1;
Todos sus pedidos también se borran. La base queda limpia, como una taza de café recién hecha.
Errores al insertar datos. Si intentas meter un pedido con un customer_id que no existe, te saldrá un error como:
ERROR: insert or update on table "orders" violates foreign key constraint
GO TO FULL VERSION