Explorar temas

INFORMÁTICA

10 ejemplos de bases de datos con tablas y consultas

Una base de datos organiza información para consultarla y actualizarla. Una nómina relaciona empleados con puestos; una biblioteca conecta ejemplares con préstamos. Estos ejemplos muestran los datos, la pregunta que queremos responder y el resultado de una consulta.

Ejemplos de bases de datos explicados

Todos los nombres, importes y registros son ficticios. Los nueve primeros casos usan tablas relacionales; el último presenta una estructura documental. Las tablas muestran los datos iniciales y, después del SQL, el resultado esperado.

Puedes leer los resultados sin programar. Para ejecutar un caso, abre «Preparar tablas y datos» y sigue las indicaciones de prueba. Las tablas anchas se pueden desplazar horizontalmente.

Ir a un ejemplo concreto
  1. Nómina: empleados y puestos
  2. Contabilidad: cuentas, subcuentas y movimientos
  3. Banca: clientes, cuentas y una transferencia
  4. Biblioteca: libros prestados y devueltos
  5. Inventario: existencias por almacén
  6. Escuela: alumnos inscritos en cursos
  7. Reservas de una sala
  8. Tienda: pedidos y líneas de compra
  9. Estación meteorológica
  10. Catálogo con documentos

EJEMPLO 01

Nómina: empleados y puestos

Una relación de uno a muchos

Una empresa ficticia guarda los puestos por separado y asigna un puesto a cada empleado. El sueldo del ejercicio pertenece al empleado: compartir puesto no obliga a cobrar lo mismo.

puestos
idnombre
1Soporte
2Ventas
empleados
idnombrepuesto_idsueldo
10Ana11200
11Luis11400
12Eva21300
Preparar tablas y datos

Ejecuta este bloque en una base nueva y vacía para este caso.

PRAGMA foreign_keys = ON;
CREATE TABLE puestos (
 id INTEGER PRIMARY KEY,
 nombre TEXT NOT NULL
);
CREATE TABLE empleados (
 id INTEGER PRIMARY KEY,
 nombre TEXT NOT NULL,
 puesto_id INTEGER NOT NULL REFERENCES puestos(id),
 sueldo INTEGER NOT NULL CHECK(sueldo >= 0)
);
INSERT INTO puestos VALUES (1, 'Soporte'), (2, 'Ventas');
INSERT INTO empleados VALUES
 (10, 'Ana', 1, 1200), (11, 'Luis', 1, 1400),
 (12, 'Eva', 2, 1300);

Consulta

SELECT e.nombre, p.nombre AS puesto, e.sueldo
FROM empleados AS e
JOIN puestos AS p ON p.id = e.puesto_id
ORDER BY e.id;
Resultado de la consulta
nombrepuestosueldo
AnaSoporte1200
LuisSoporte1400
EvaVentas1300

La clave foránea puesto_id apunta a un puesto existente. JOIN combina los datos relacionados para mostrar el nombre del puesto junto al empleado. Los importes son unidades monetarias enteras de un modelo didáctico; no se calcula una nómina legal completa.

Qué puede fallar: Asignar puesto_id = 99 se rechaza porque no existe ese puesto. La restricción no comprueba si el puesto elegido es realmente el de la persona.

EJEMPLO 02

Contabilidad: cuentas, subcuentas y movimientos

Agrupar y calcular

Este registro simplificado clasifica movimientos por subcuenta. No representa un sistema completo de asientos por partida doble.

cuentas
idnombregrupo
1IngresosResultados
subcuentas
idcuenta_idnombre
111Ventas de libros
121Talleres
movimientos
idsubcuenta_idimporte
111100
21150
31280
Preparar tablas y datos

Ejecuta este bloque en una base nueva y vacía para este caso.

PRAGMA foreign_keys = ON;
CREATE TABLE cuentas (
 id INTEGER PRIMARY KEY, nombre TEXT NOT NULL,
 grupo TEXT NOT NULL
);
CREATE TABLE subcuentas (
 id INTEGER PRIMARY KEY,
 cuenta_id INTEGER NOT NULL REFERENCES cuentas(id),
 nombre TEXT NOT NULL
);
CREATE TABLE movimientos (
 id INTEGER PRIMARY KEY,
 subcuenta_id INTEGER NOT NULL REFERENCES subcuentas(id),
 importe INTEGER NOT NULL
);
INSERT INTO cuentas VALUES (1, 'Ingresos', 'Resultados');
INSERT INTO subcuentas VALUES
 (11, 1, 'Ventas de libros'), (12, 1, 'Talleres');
INSERT INTO movimientos VALUES
 (1, 11, 100), (2, 11, 50), (3, 12, 80);

Consulta

SELECT s.nombre, SUM(m.importe) AS total
FROM subcuentas AS s
JOIN movimientos AS m ON m.subcuenta_id = s.id
GROUP BY s.id, s.nombre
ORDER BY s.id;
Resultado de la consulta
nombretotal
Ventas de libros150
Talleres80

La consulta obtiene un dato calculado: el total de cada subcuenta. Los movimientos se conservan por separado para poder explicar de dónde procede cada suma. El grupo contable se registra en cuentas; no se repite en cada movimiento.

Qué puede fallar: Una suma correcta puede partir de importes incorrectos. La base guarda lo que se registra: se necesitan revisión, respaldo documental y reglas de acceso.

EJEMPLO 03

Banca: clientes, cuentas y una transferencia

Confirmar cambios juntos

Dos cuentas ficticias pertenecen a clientes distintos. El ejercicio transfiere 40 unidades de A a B, sin comisiones y dentro de una misma base de datos.

clientes
idnombre
1Ana
2Luis
cuentas
idcliente_idsaldo
A1500
B2100
Preparar tablas y datos

Ejecuta este bloque en una base nueva y vacía para este caso.

PRAGMA foreign_keys = ON;
CREATE TABLE clientes (
 id INTEGER PRIMARY KEY, nombre TEXT NOT NULL
);
CREATE TABLE cuentas (
 id TEXT PRIMARY KEY NOT NULL,
 cliente_id INTEGER NOT NULL REFERENCES clientes(id),
 saldo INTEGER NOT NULL CHECK(saldo >= 0)
);
INSERT INTO clientes VALUES (1, 'Ana'), (2, 'Luis');
INSERT INTO cuentas VALUES ('A', 1, 500), ('B', 2, 100);

Transferencia: ejecutar una vez

BEGIN;
UPDATE cuentas SET saldo = saldo - 40 WHERE id = 'A';
UPDATE cuentas SET saldo = saldo + 40 WHERE id = 'B';
COMMIT;

Consulta

SELECT id, saldo FROM cuentas ORDER BY id;
Resultado de la consulta
idsaldo
A460
B140

La transacción agrupa ambas modificaciones. Tras COMMIT, los saldos suman 600, igual que antes. Si se decide cancelar antes de confirmar, ROLLBACK deshace los cambios de esa transacción. En una aplicación también hay que validar que las dos cuentas existen y comprobar cuántas filas se actualizan. [3]

Qué puede fallar: Una transacción no reconoce por sí sola al destinatario correcto ni autoriza al usuario. Ante un error, la aplicación debe manejarlo y cancelar cuando corresponda; no debe continuar hasta confirmar una operación parcial.

EJEMPLO 04

Biblioteca: libros prestados y devueltos

Consultar un valor ausente

Cada ejemplar físico tiene un identificador. Un préstamo sin fecha de devolución todavía está abierto en este registro.

ejemplares
idtitulo
1Atlas del cielo
2Atlas del cielo
prestamos
idejemplar_iddevuelto
101NULL
1122026-09-30
Preparar tablas y datos

Ejecuta este bloque en una base nueva y vacía para este caso.

PRAGMA foreign_keys = ON;
CREATE TABLE ejemplares (
 id INTEGER PRIMARY KEY, titulo TEXT NOT NULL
);
CREATE TABLE prestamos (
 id INTEGER PRIMARY KEY,
 ejemplar_id INTEGER NOT NULL REFERENCES ejemplares(id),
 devuelto TEXT
);
INSERT INTO ejemplares VALUES
 (1, 'Atlas del cielo'), (2, 'Atlas del cielo');
INSERT INTO prestamos VALUES
 (10, 1, NULL), (11, 2, '2026-09-30');

Consulta

SELECT p.id AS prestamo, e.titulo
FROM prestamos AS p
JOIN ejemplares AS e ON e.id = p.ejemplar_id
WHERE p.devuelto IS NULL
ORDER BY p.id;
Resultado de la consulta
prestamotitulo
10Atlas del cielo

IS NULL busca ausencia de valor: no equivale a una cadena vacía ni a la palabra «NULL». Dos ejemplares pueden compartir título; por eso el título no se usa como identificador de la copia.

Qué puede fallar: La clave foránea acredita que el ejemplar existe, pero este esquema todavía no impide dos préstamos abiertos para la misma copia. Esa regla requiere otro control.

EJEMPLO 05

Inventario: existencias por almacén

Una clave de dos columnas

El producto A está en dos almacenes. Lo que debe ser único es la combinación de producto y almacén.

existencias
productoalmacencantidad
ANorte8
ASur5
BNorte3
Preparar tablas y datos

Ejecuta este bloque en una base nueva y vacía para este caso.

PRAGMA foreign_keys = ON;
CREATE TABLE existencias (
 producto TEXT NOT NULL,
 almacen TEXT NOT NULL,
 cantidad INTEGER NOT NULL CHECK(cantidad >= 0),
 PRIMARY KEY(producto, almacen)
);
INSERT INTO existencias VALUES
 ('A', 'Norte', 8), ('A', 'Sur', 5), ('B', 'Norte', 3);

Consulta

SELECT producto, SUM(cantidad) AS unidades
FROM existencias
GROUP BY producto
ORDER BY producto;
Resultado de la consulta
productounidades
A13
B3

La clave primaria compuesta permite repetir A en almacenes distintos, pero no registrar dos filas A–Norte. La consulta suma existencias por producto, sin perder el detalle de ubicación.

Qué puede fallar: CHECK rechaza cantidades negativas, pero no detecta que alguien introdujo 80 cuando había 8. La validez del formato y la exactitud del dato son cosas diferentes.

EJEMPLO 06

Escuela: alumnos inscritos en cursos

Una relación de muchos a muchos

Un alumno puede cursar varias materias y un curso puede tener varios alumnos. Una tabla intermedia registra cada inscripción.

alumnos
idnombre
1Eva
2Leo
cursos
idnombre
10Arte
20Ciencias
inscripciones
alumno_idcurso_id
110
120
220
Preparar tablas y datos

Ejecuta este bloque en una base nueva y vacía para este caso.

PRAGMA foreign_keys = ON;
CREATE TABLE alumnos (
 id INTEGER PRIMARY KEY, nombre TEXT NOT NULL
);
CREATE TABLE cursos (
 id INTEGER PRIMARY KEY, nombre TEXT NOT NULL
);
CREATE TABLE inscripciones (
 alumno_id INTEGER NOT NULL REFERENCES alumnos(id),
 curso_id INTEGER NOT NULL REFERENCES cursos(id),
 PRIMARY KEY(alumno_id, curso_id)
);
INSERT INTO alumnos VALUES (1, 'Eva'), (2, 'Leo');
INSERT INTO cursos VALUES (10, 'Arte'), (20, 'Ciencias');
INSERT INTO inscripciones VALUES (1, 10), (1, 20), (2, 20);

Consulta

SELECT a.nombre AS alumno, c.nombre AS curso
FROM inscripciones AS i
JOIN alumnos AS a ON a.id = i.alumno_id
JOIN cursos AS c ON c.id = i.curso_id
ORDER BY a.id, c.id;
Resultado de la consulta
alumnocurso
EvaArte
EvaCiencias
LeoCiencias

La tabla intermedia representa una relación. Esto muestra por qué no toda tabla tiene que representar una entidad como «persona» o «curso». Cada fila combina dos claves.

Qué puede fallar: Inscribir de nuevo a Eva en Arte genera un conflicto de clave primaria. Si se necesitan cursos por año, el modelo debe distinguir también las ediciones o periodos.

EJEMPLO 07

Reservas de una sala

Unicidad de una franja

Un centro cultural reserva una sala mediante franjas fijas de una hora. La fecha y la hora se guardan con el mismo formato.

reservas
idsalainicio
1A2026-10-12 10:00
2A2026-10-12 11:00
3B2026-10-12 10:00
Preparar tablas y datos

Ejecuta este bloque en una base nueva y vacía para este caso.

PRAGMA foreign_keys = ON;
CREATE TABLE reservas (
 id INTEGER PRIMARY KEY,
 sala TEXT NOT NULL,
 inicio TEXT NOT NULL,
 UNIQUE(sala, inicio)
);
INSERT INTO reservas VALUES
 (1, 'A', '2026-10-12 10:00'),
 (2, 'A', '2026-10-12 11:00'),
 (3, 'B', '2026-10-12 10:00');

Consulta

SELECT sala, inicio FROM reservas
WHERE inicio = '2026-10-12 10:00'
ORDER BY sala;
Resultado de la consulta
salainicio
A2026-10-12 10:00
B2026-10-12 10:00

UNIQUE(sala, inicio) impide repetir la misma franja para la misma sala. Reservar otra sala a esa hora sí es válido.

Qué puede fallar: Esta restricción no valida fechas ni detecta cualquier solapamiento. Si las duraciones fueran variables, dos inicios distintos podrían superponerse y haría falta otra regla.

EJEMPLO 08

Tienda: pedidos y líneas de compra

Calcular un total sin repetir datos del pedido

Un pedido reúne varias líneas. El precio de cada línea es el acordado al comprar, no necesariamente el precio actual del catálogo.

pedidos
idcliente
50Mara
lineas
pedido_idnumerocantidadprecio_cent
5012300
5021450
Preparar tablas y datos

Ejecuta este bloque en una base nueva y vacía para este caso.

PRAGMA foreign_keys = ON;
CREATE TABLE pedidos (
 id INTEGER PRIMARY KEY, cliente TEXT NOT NULL
);
CREATE TABLE lineas (
 pedido_id INTEGER NOT NULL REFERENCES pedidos(id),
 numero INTEGER NOT NULL,
 cantidad INTEGER NOT NULL CHECK(cantidad > 0),
 precio_cent INTEGER NOT NULL CHECK(precio_cent >= 0),
 PRIMARY KEY(pedido_id, numero)
);
INSERT INTO pedidos VALUES (50, 'Mara');
INSERT INTO lineas VALUES (50, 1, 2, 300), (50, 2, 1, 450);

Consulta

SELECT pedido_id,
 SUM(cantidad * precio_cent) AS total_cent
FROM lineas
GROUP BY pedido_id
ORDER BY pedido_id;
Resultado de la consulta
pedido_idtotal_cent
501050

El total es 1.050 centavos, equivalentes a 10,50 unidades monetarias en una moneda de cien centavos por unidad. Guardar enteros evita representar esos importes mediante aproximaciones de coma flotante. Aquí no se añaden impuestos ni descuentos.

Qué puede fallar: Recalcular una venta antigua con el precio actual alteraría su historia. Reducir redundancia no significa borrar datos que describen condiciones distintas.

EJEMPLO 09

Estación meteorológica

Datos ordenados en el tiempo

Una estación registra tres temperaturas. El instante es parte de la identidad de cada lectura.

lecturas
estacioninstantetemperatura
N2026-10-01 08:0018
N2026-10-01 09:0020
N2026-10-01 10:0022
Preparar tablas y datos

Ejecuta este bloque en una base nueva y vacía para este caso.

PRAGMA foreign_keys = ON;
CREATE TABLE lecturas (
 estacion TEXT NOT NULL,
 instante TEXT NOT NULL,
 temperatura REAL NOT NULL,
 PRIMARY KEY(estacion, instante)
);
INSERT INTO lecturas VALUES
 ('N', '2026-10-01 08:00', 18),
 ('N', '2026-10-01 09:00', 20),
 ('N', '2026-10-01 10:00', 22);

Consulta

SELECT estacion, AVG(temperatura) AS media
FROM lecturas
GROUP BY estacion
ORDER BY estacion;
Resultado de la consulta
estacionmedia
N20.0

La media aritmética de estas tres lecturas es 20 °C. Una colección de observaciones temporales también puede guardarse en tablas relacionales; describir los datos como «serie temporal» no obliga a usar un único tipo de gestor.

Qué puede fallar: Tres medidas no bastan para llamar al resultado «temperatura media del día». Para combinar estaciones hay que definir unidades, horarios, zona horaria y tratamiento de lecturas ausentes.

EJEMPLO 10

Catálogo con documentos

Otra forma de organizar los datos

Una base documental puede representar cada producto mediante un documento con campos y estructuras anidadas. Este JSON ilustra un producto ficticio; no es una consulta ejecutada en un gestor.

{
  "id": "P-07",
  "nombre": "Mochila",
  "atributos": {
    "capacidad_l": 20,
    "color": "azul"
  },
  "etiquetas": [
    "viaje",
    "urbana"
  ]
}

El color se encuentra dentro de atributos; etiquetas contiene dos elementos. En MongoDB los documentos se almacenan en BSON, una representación binaria con tipos adicionales a JSON. El ejemplo solo ilustra la estructura: no se ha ejecutado en MongoDB. [9]

Qué puede fallar: Una estructura flexible también necesita criterios de validación. Mezclar capacidad_l con capacidad_ml sin definir unidades puede producir comparaciones incorrectas. Documental no significa «sin reglas».

Tablas, claves y relaciones

En una base relacional, una tabla organiza filas y columnas. Una fila es un registro; una columna contiene un atributo como nombre o fecha. Una entidad es un concepto del dominio, como empleado o curso: puede representarse en tablas, pero no son términos intercambiables. Una tabla también puede representar la relación entre entidades, como una inscripción.

Las restricciones expresan reglas concretas: NOT NULL exige un valor; UNIQUE evita duplicados según las columnas elegidas; CHECK evalúa una condición. Las reglas necesitan un diseño adecuado y no acreditan la veracidad de los datos.

[1] [2]

Separar información puede reducir repeticiones innecesarias: el nombre del puesto se guarda una vez y se consulta mediante su clave. Sin embargo, repetir una clave foránea es normal; conservar el precio pactado en una compra también tiene sentido aunque exista otro precio en el catálogo.

Cómo probar el SQL de los ejemplos

Los nueve casos relacionales se ejecutaron con SQLite 3.53.1. Cada caso es independiente: utiliza una base nueva y vacía, ejecuta su bloque de preparación y después su consulta. En banca, ejecuta la transferencia una sola vez antes de consultar.

  1. La preparación crea las tablas e introduce exactamente los registros mostrados.
  2. PRAGMA foreign_keys = ON activa la comprobación de referencias en esa conexión, antes de iniciar una transacción.
  3. SELECT elige columnas; JOIN combina registros relacionados; WHERE filtra; GROUP BY agrupa y ORDER BY fija el orden del resultado.
  4. El resultado debe coincidir con la tabla que sigue al SQL.

Los códigos están escritos para SQLite; no se afirma compatibilidad idéntica con todos los gestores. Los nombres de tablas se repiten entre algunos ejercicios, por eso deben probarse por separado. Repetir una preparación sobre las tablas ya creadas produce un error.

Son esquemas de aprendizaje. No incorporan todos los permisos, controles de fechas, tipos estrictos ni reglas que exigiría una aplicación completa. Las restricciones de los ejemplos cubren únicamente las condiciones declaradas. [1] [2]

La base de datos no es el gestor

La base de datos es la colección organizada de datos. El sistema gestor de bases de datos, SGBD o DBMS, es el software que permite definirla, consultar y modificar su contenido y administrar su acceso. Un sistema de nómina utiliza una base de datos, pero incluye además pantallas, reglas y procesos.

[5]

Oracle Database, MySQL y SQL Server son ejemplos de gestores con modelo relacional. Informix combina capacidades relacionales con soporte para otros modelos. Progress OpenEdge RDBMS también es un gestor relacional. Estos nombres identifican herramientas, no bases concretas como «los préstamos de una biblioteca» ni una clasificación de popularidad.

[4] [5] [6] [7] [8]

Compartir datos entre usuarios es posible mediante el gestor y la aplicación, pero requiere permisos y coordinación de operaciones. Guardar mucha información no garantiza consultas rápidas: también influyen el diseño, los índices, las consultas y los recursos disponibles.

Ocho ejercicios para practicar

  1. En nómina, ¿pueden Ana y Luis compartir puesto_id = 1?
  2. ¿Qué sucede al asignar un puesto inexistente con la clave foránea activada?
  3. ¿Cuánto suman los movimientos contables mostrados?
  4. ¿Por qué buscar préstamos con IS NULL?
  5. ¿Cuántas inscripciones aparecen para Eva?
  6. ¿UNIQUE(sala, inicio) evita toda reserva superpuesta?
  7. ¿Cuál sería el total de dos unidades a 300 centavos y tres a 450?
  8. ¿Usar tablas, claves y transacciones garantiza que los datos sean verdaderos?
Ver respuestas explicadas
  1. Sí. La clave primaria de empleados es id; puesto_id puede repetirse porque varios empleados pueden tener el mismo puesto.
  2. La inserción se rechaza. Eso exige que la restricción esté declarada y que su comprobación esté activada en la conexión.
  3. 230 unidades: 100 + 50 + 80. Por subcuenta son 150 y 80.
  4. Porque una devolución ausente se representa con NULL. No se compara con = NULL ni con la cadena de texto «NULL».
  5. Dos: Arte y Ciencias. La pareja alumno–curso identifica cada inscripción.
  6. No. Evita repetir la misma pareja; duraciones variables exigen comprobar intervalos y otras condiciones.
  7. 1.950 centavos: 2 × 300 + 3 × 450, equivalentes a 19,50 unidades en este modelo.
  8. No. Los controles detectan determinadas inconsistencias; no comprueban automáticamente la veracidad de nombres, importes o decisiones.

Errores frecuentes

Referencias

  1. SQLite · CREATE TABLE. Claves y restricciones de las tablas de los ejercicios.
  2. SQLite · Foreign Key Support. Declaración y activación de claves foráneas.
  3. SQLite · Transactions. Confirmación, cancelación y tratamiento de errores.
  4. Oracle · Bases de datos relacionales. Tablas, filas, columnas y relaciones.
  5. MySQL 8.4 · What is MySQL?. Base de datos, gestor y modelo relacional.
  6. Microsoft · What is SQL Server?. Clasificación de SQL Server como gestor relacional.
  7. IBM · Informix. Capacidades relacionales y soporte de otros modelos.
  8. Progress · RDBMS architecture. Modelo relacional de OpenEdge RDBMS.
  9. MongoDB · Documents. Documentos BSON y estructuras anidadas.