Práctica SQL · de inicial a intermedio

8 ejercicios SQL resueltos

Practica de SELECT a JOIN con una base descargable, soluciones explicadas y resultados que puedes comprobar en el editor.

Actualizado: 27 septiembre 2026Ejemplos explicados
Contenido de esta guía

Cómo practicar con estos ejercicios

Estos ocho ejercicios SQL resueltos avanzan desde filtros hasta consultas con JOIN y agrupaciones. Todos usan la base ficticia TiendaSQL del sitio y se han ejecutado sobre el archivo SQLite descargable. Intenta cada reto antes de abrir su solución; compara las filas devueltas y luego modifica la consulta.

Abre el Editor SQL para ejecutar las consultas en el navegador. También puedes descargar la base SQLite y usarla en tu equipo. El editor carga la misma base educativa. No necesitas una cuenta.

Ejercicios SQL con solución

Usaremos cuatro tablas: clientes (id, nombre, ciudad, activo), productos (id, nombre, precio, stock), pedidos (id, cliente_id, estado, total) y detalle_pedido (pedido_id, producto_id, cantidad). Cada resultado esperado corresponde a la versión actual de TiendaSQL.

1. Filtra clientes activos de Madrid

Inicial · SELECT y WHERE

Tu reto

Muestra el nombre y la ciudad de los clientes activos de Madrid, ordenados por nombre. En esta base, activo = 1 significa que el cliente está activo.

Antes de ejecutar: predice cuántas filas devolverá tu consulta.

Ver solución y resultado esperado
Solución del ejercicio 1
SELECT nombre, ciudad
FROM clientes
WHERE activo = 1 AND ciudad = 'Madrid'
ORDER BY nombre;

Resultado comprobado: 3 filas: Ana Torres, Marta Ruiz y Noa Vidal (todas de Madrid).

Primero filtra las filas; después ordena las que cumplen ambas condiciones. Sin ORDER BY, el orden no está garantizado.

Prueba una variante: Cambia Madrid por Valencia y comprueba cuántos clientes activos hay.

2. Encuentra productos con poco stock

Inicial · filtros y orden

Tu reto

Lista nombre y stock de los productos con menos de 10 unidades. Ordena primero por stock ascendente y después por nombre.

Antes de ejecutar: predice cuántas filas devolverá tu consulta.

Ver solución y resultado esperado
Solución del ejercicio 2
SELECT nombre, stock
FROM productos
WHERE stock < 10
ORDER BY stock ASC, nombre ASC;

Resultado comprobado: 6 filas. Los dos primeros son Altavoz y Portátil Pro, ambos con stock 0; el último es Disco SSD con 9.

El segundo criterio resuelve el empate de stock cero. El filtro < 10 también incluye cero.

Prueba una variante: Cambia el umbral a stock <= 4 y predice qué productos quedan.

3. Cuenta las ciudades distintas

Inicial · DISTINCT

Tu reto

Obtén una lista alfabética de ciudades de clientes sin duplicados. Devuelve solo la columna ciudad.

Antes de ejecutar: predice cuántas filas devolverá tu consulta.

Ver solución y resultado esperado
Solución del ejercicio 3
SELECT DISTINCT ciudad
FROM clientes
ORDER BY ciudad;

Resultado comprobado: 6 ciudades: A Coruña, Bilbao, Madrid, Sevilla, Valencia y Zaragoza.

DISTINCT elimina repeticiones de la columna seleccionada; no cuenta clientes. Si quieres contar ciudades, envuelve esta idea en COUNT(DISTINCT ciudad).

Prueba una variante: Escribe la consulta que devuelva solo el número de ciudades distintas.

4. Muestra los tres productos más caros

Inicial · ORDER BY y LIMIT

Tu reto

Devuelve nombre y precio de los tres productos con mayor precio. Usa el id para desempatar precios iguales.

Antes de ejecutar: predice cuántas filas devolverá tu consulta.

Ver solución y resultado esperado
Solución del ejercicio 4
SELECT nombre, precio
FROM productos
ORDER BY precio DESC, id
LIMIT 3;

Resultado comprobado: Portátil Pro (999), Monitor 27 (249) y Monitor 24 (179), en ese orden.

DESC coloca primero el precio más alto. En SQLite, LIMIT 3 conserva tres filas; SQL Server usaría TOP (3).

Prueba una variante: Muestra los tres más baratos cambiando el sentido del orden.

5. Resume pedidos por estado

Intermedio · GROUP BY

Tu reto

Cuenta cuántos pedidos hay en cada estado. Ordena por cantidad descendente y, para empates, por nombre del estado.

Antes de ejecutar: predice cuántas filas devolverá tu consulta.

Ver solución y resultado esperado
Solución del ejercicio 5
SELECT estado, COUNT(*) AS cantidad
FROM pedidos
GROUP BY estado
ORDER BY COUNT(*) DESC, estado;

Resultado comprobado: enviado: 9; pendiente: 6; cancelado: 3.

Cada grupo reúne pedidos con el mismo estado. COUNT(*) cuenta las filas de ese grupo y la ordenación compara el tamaño de los grupos.

Prueba una variante: Filtra con HAVING COUNT(*) >= 6 antes de ordenar.

6. Resume pedidos e importes por cliente

Intermedio · INNER JOIN y SUM

Tu reto

Muestra los tres clientes con mayor suma de pedidos.total, sin excluir estados. Devuelve nombre, número de pedidos y total redondeado a dos decimales.

Antes de ejecutar: predice cuántas filas devolverá tu consulta.

Ver solución y resultado esperado
Solución del ejercicio 6
SELECT c.nombre,
       COUNT(p.id) AS pedidos,
       ROUND(SUM(p.total), 2) AS total
FROM clientes AS c
JOIN pedidos AS p ON p.cliente_id = c.id
GROUP BY c.id, c.nombre
ORDER BY SUM(p.total) DESC, c.id
LIMIT 3;

Resultado comprobado: Marta Ruiz: 3 pedidos y 1214,90; Sara Gómez: 2 y 1112,00; Ana Torres: 3 y 402,30.

El JOIN conecta cada pedido con su cliente; agrupar por id evita mezclar personas que podrían compartir nombre. Se suman todos los estados, incluidos pedidos cancelados, así que este importe no equivale a ingresos efectivos. El editor puede mostrar 1214.9: es el mismo valor numérico que 1214,90; ROUND no fija el formato visual.

Prueba una variante: Añade WHERE p.estado != 'cancelado' antes de GROUP BY y observa el cambio.

7. Localiza clientes sin pedidos

Intermedio · LEFT JOIN

Tu reto

Devuelve los nombres de clientes para los que no existe ninguna fila en pedidos, en orden alfabético.

Antes de ejecutar: predice cuántas filas devolverá tu consulta.

Ver solución y resultado esperado
Solución del ejercicio 7
SELECT c.nombre
FROM clientes AS c
LEFT JOIN pedidos AS p ON p.cliente_id = c.id
WHERE p.id IS NULL
ORDER BY c.nombre;

Resultado comprobado: 2 filas: Mario Gil y Pablo Sanz.

El LEFT JOIN conserva a todos los clientes. Cuando falta un pedido correspondiente, las columnas de p son NULL; el filtro selecciona esos casos.

Prueba una variante: Resuelve el mismo reto con NOT EXISTS y compara los resultados.

8. Cuenta unidades por producto en los pedidos

Intermedio · JOIN y agregación

Tu reto

Suma detalle_pedido.cantidad para cada producto y muestra los tres con más unidades. En empates, ordena por id de producto.

Antes de ejecutar: predice cuántas filas devolverá tu consulta.

Ver solución y resultado esperado
Solución del ejercicio 8
SELECT pr.nombre, SUM(d.cantidad) AS unidades
FROM productos AS pr
JOIN detalle_pedido AS d ON d.producto_id = pr.id
GROUP BY pr.id, pr.nombre
ORDER BY SUM(d.cantidad) DESC, pr.id
LIMIT 3;

Resultado comprobado: Cable USB-C: 6 unidades; Ratón: 4; Auriculares: 4.

La pregunta es por unidades, por eso se usa SUM(cantidad) en lugar de COUNT(*). Aquí se incluyen detalles de pedidos cancelados porque no se ha unido ni filtrado la tabla pedidos.

Prueba una variante: Une también pedidos y excluye los cancelados; explica por qué cambia el ranking.

Después de resolverlos

Si fallaste en los primeros cuatro, repasa SELECT, WHERE y orden y límites. Para los últimos, practica GROUP BY, INNER JOIN y LEFT JOIN. Después prueba el proyecto de análisis de ventas sin mirar las soluciones.

Los ejemplos están escritos para SQLite. PostgreSQL y MySQL comparten gran parte de esta sintaxis; en SQL Server cambia LIMIT por TOP u OFFSET ... FETCH, según la consulta.

Fuentes y datos