Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/tutosrive/db-relacionales-2026-1/llms.txt

Use this file to discover all available pages before exploring further.

Esta práctica utiliza una base de datos de una cadena de tiendas de bicicletas para desarrollar habilidades progresivas en SQL: desde consultas simples con JOIN hasta subconsultas correlacionadas, agregaciones con HAVING y análisis de inventario. El esquema modela un negocio real con productos, clientes, personal, pedidos y tiendas, lo que permite plantear preguntas de negocio genuinas y responderlas con SQL. El objetivo no es solo que las consultas funcionen, sino que puedas leer el plan de ejecución y entender por qué son eficientes o dónde hay oportunidad de mejora.

Esquema de la base de datos

El esquema está compuesto por nueve tablas que representan las entidades principales de la cadena de tiendas.
TablaColumnas claveDescripción
categoriascategoria_id PK, nombreCategorías de productos (Mountain Bike, Road Bike, etc.)
marcasmarca_id PK, nombreFabricantes de bicicletas y componentes
productosproducto_id PK, marca_id FK, categoria_id FK, año_modelo, precio_listaCatálogo de productos
clientescliente_id PK, nombre, apellido, telefono, email, ciudad, estadoClientes registrados
tiendastienda_id PK, nombre, telefono, email, ciudad, estadoSucursales de la cadena
personalpersonal_id PK, tienda_id FK, gerente_id FKEmpleados; gerente_id es autorreferencial
pedidospedido_id PK, cliente_id FK, tienda_id FK, personal_id FK, estado, fecha_pedido, fecha_requerida, fecha_envioÓrdenes de compra
items_pedidopedido_id FK, item_id, producto_id FK, cantidad, precio_lista, descuentoLíneas de cada pedido
inventariotienda_id FK, producto_id FK, cantidadStock por tienda

Relaciones del esquema

marcas ──────┐

categorias → productos ← inventario ← tiendas
                ↓                         ↑
           items_pedido → pedidos ─────────┤
                              ↑            │
                           clientes    personal
Usa EXPLAIN ANALYZE antes de cualquier consulta compleja para ver el plan de ejecución real. Por ejemplo: EXPLAIN ANALYZE SELECT .... Presta atención a los nodos Seq Scan en tablas grandes; suelen indicar que falta un índice. En la práctica compararemos los planes de consultas con y sin índices sobre las columnas de join.

Consultas de práctica

Nivel básico: JOINs y filtros simples

Estas consultas practican la navegación por el esquema mediante JOIN y el filtrado con WHERE. Asegúrate de entender el tipo de join que estás usando y por qué.Productos con su marca y categoría
-- Productos con su marca y categoría, ordenados por precio descendente
SELECT
  p.nombre        AS producto,
  m.nombre        AS marca,
  c.nombre        AS categoria,
  p.precio_lista
FROM productos p
JOIN marcas     m ON p.marca_id     = m.marca_id
JOIN categorias c ON p.categoria_id = c.categoria_id
ORDER BY p.precio_lista DESC;
Pedidos pendientes de envío
-- Pedidos con estado 'Pendiente' que ya pasaron su fecha requerida
SELECT
  o.pedido_id,
  c.nombre || ' ' || c.apellido  AS cliente,
  o.fecha_pedido,
  o.fecha_requerida,
  t.nombre                        AS tienda
FROM pedidos o
JOIN clientes c ON o.cliente_id = c.cliente_id
JOIN tiendas  t ON o.tienda_id  = t.tienda_id
WHERE o.estado = 1                           -- 1 = Pendiente
  AND o.fecha_requerida < CURRENT_DATE
  AND o.fecha_envio IS NULL
ORDER BY o.fecha_requerida ASC;
Inventario de una tienda específica
-- Stock completo de la tienda con tienda_id = 1
SELECT
  pr.nombre   AS producto,
  cat.nombre  AS categoria,
  i.cantidad
FROM inventario i
JOIN productos  pr  ON i.producto_id  = pr.producto_id
JOIN categorias cat ON pr.categoria_id = cat.categoria_id
WHERE i.tienda_id = 1
ORDER BY cat.nombre, pr.nombre;

Ejercicios

Resuelve los siguientes retos usando el esquema de bicicletas. Intenta escribir la consulta antes de expandir la solución propuesta.
Encuentra la tienda que generó el mayor revenue total (suma de cantidad × precio_lista × (1 - descuento)) en los pedidos del último año calendario. Muestra el nombre de la tienda, el número de pedidos y el revenue.Solución:
SELECT
  t.nombre                                                   AS tienda,
  COUNT(DISTINCT o.pedido_id)                                AS total_pedidos,
  SUM(i.cantidad * i.precio_lista * (1 - i.descuento))       AS revenue
FROM tiendas t
JOIN pedidos      o ON t.tienda_id   = o.tienda_id
JOIN items_pedido i ON o.pedido_id   = i.pedido_id
WHERE o.fecha_pedido >= DATE_TRUNC('year', CURRENT_DATE - INTERVAL '1 year')
  AND o.fecha_pedido <  DATE_TRUNC('year', CURRENT_DATE)
GROUP BY t.tienda_id, t.nombre
ORDER BY revenue DESC
LIMIT 1;
Encuentra todos los productos que existen en la tabla productos pero que no tienen ninguna línea en items_pedido (es decir, nunca han sido vendidos). Muestra el nombre del producto, la marca y la categoría.Solución:
SELECT
  p.nombre   AS producto,
  m.nombre   AS marca,
  c.nombre   AS categoria
FROM productos  p
JOIN marcas     m ON p.marca_id     = m.marca_id
JOIN categorias c ON p.categoria_id = c.categoria_id
WHERE NOT EXISTS (
  SELECT 1
  FROM items_pedido i
  WHERE i.producto_id = p.producto_id
)
ORDER BY c.nombre, p.nombre;
El campo gerente_id en la tabla personal es una autorreferencia (cada empleado puede tener un gerente que también es personal). Escribe una consulta que muestre cada empleado junto con el nombre de su gerente directo. Los empleados sin gerente (gerentes de tienda) deben aparecer con NULL en la columna de gerente.Solución:
SELECT
  e.personal_id,
  e.nombre || ' ' || e.apellido    AS empleado,
  t.nombre                          AS tienda,
  g.nombre || ' ' || g.apellido    AS gerente_directo
FROM personal e
JOIN tiendas  t  ON e.tienda_id  = t.tienda_id
LEFT JOIN personal g ON e.gerente_id = g.personal_id
ORDER BY t.nombre, gerente_directo NULLS FIRST, empleado;

Build docs developers (and LLMs) love