Para docentes
Un juego de detectives que se resuelve escribiendo SQL real contra una base de datos real, no marcando opciones.
Cada caso de Caso Abierto es una base de datos. El alumno escribe SQL real, con DuckDB, que sigue el estándar SQL en lo básico.
Para cerrar un caso entrega la consulta que demuestra su respuesta, y el juego la rechaza si sólo la afirma en vez de probarla con datos.
Cuatro temporadas. La tabla sale del mismo catálogo que usa el juego. La columna «trampa» enlaza a la página que explica, con SQL de verdad, el error que ese caso obliga a encontrar.
| Nº | Caso | Dificultad | Técnicas | Trampa |
|---|---|---|---|---|
| 0 | La primera consulta | ◆◇◇◇◇ | SELECT, WHERE, una condición de hora | |
| 1 | El expediente que nadie pidió | ◆◇◇◇◇ | SELECT, WHERE, rangos de fechas, ORDER BY | ¿Por qué BETWEEN se come el último día del rango? |
| 2 | La descripción del testigo | ◆◇◇◇◇ | WHERE compuesto, LIKE, IN, BOOLEAN, NULL | |
| 3 | La llamada de las 23:40 | ◆◆◇◇◇ | JOIN, alias de tabla, encadenar dos joins | |
| 4 | El habitual | ◆◆◇◇◇ | GROUP BY, COUNT, HAVING, filtrar antes y después de agrupar | ¿Por qué el WHERE no encuentra a quien 'siempre' paga en efectivo? |
| 5 | Once coartadas y una que no | ◆◆◆◇◇ | LEFT JOIN, NOT EXISTS, anti-join, solape de intervalos | ¿Cuándo se solapan de verdad dos intervalos de tiempo? |
| 6 | El reservado 3 | ◆◆◆◇◇ | self-join, WITH (CTE), solape de intervalos, excluirse a uno mismo | ¿Por qué un self-join siempre trae una fila de más? |
| 7 | La tarjeta que estaba en dos sitios | ◆◆◆◆◇ | window functions, LAG, PARTITION BY, QUALIFY, date_diff | ¿Por qué el saldo acumulado repite el mismo número en dos filas distintas? · ¿Por qué WHERE no puede filtrar el resultado de una window function? |
| 8 | Lo que trajo el Anacleta | ◆◆◆◆◆ | CTEs encadenados, múltiples JOIN, solape, aritmética de fechas, razonar en pasos |
| Nº | Caso | Dificultad | Técnicas | Trampa |
|---|---|---|---|---|
| 1 | La cuenta que sangra | ◆◆◇◇◇ | SUM, GROUP BY, aritmética de costes, ORDER BY | |
| 2 | Operar contra el espejo | ◆◆◆◇◇ | JOIN de una tabla por dos claves, comparar dos lados de la misma fila, GROUP BY | |
| 3 | El asiento que nadie escribió | ◆◆◆◇◇ | anti-join, NOT EXISTS, LEFT JOIN ... IS NULL, la trampa de NOT IN con NULL | ¿Por qué NOT IN devuelve cero filas? |
| 4 | El colector que se quedó pillado | ◆◆◆◇◇ | LAG, gaps and islands, row_number, detección de rachas, calidad de datos | |
| 5 | El que sabía | ◆◆◆◆◇ | join por intervalo, ASOF JOIN, tasa de acierto, tamaño de muestra | Una tasa sin denominador no significa nada |
| 6 | El señuelo | ◆◆◆◆◇ | FILTER, ratios condicionales, percentiles, combinar varias condiciones | |
| 7 | El peaje | ◆◆◆◆◆ | date_part, cohortes por hora, teórico vs real, descomponer un resultado, puntos básicos | |
| 8 | Sigue el dinero | ◆◆◆◆◆ | WITH RECURSIVE, grafos en SQL, control de ciclos, cuenta terminal |
| Nº | Caso | Dificultad | Técnicas | Trampa |
|---|---|---|---|---|
| 1 | El informe que se multiplicó solo | ◆◆◆◇◇ | cardinalidad, fan-out, agregar antes de unir, COUNT DISTINCT | El join que multiplica filas |
| 2 | El doble | ◆◆◆◇◇ | deduplicación, row_number, QUALIFY, clave de negocio vs fila | |
| 3 | La tarifa de ayer | ◆◆◆◆◇ | tablas con historial, join temporal, valido_desde / valido_hasta, recalcular y comparar | |
| 4 | La unidad muda | ◆◆◆◆◇ | normalizar unidades, conversión de divisa, leer el diccionario de datos, CASE | |
| 5 | El día de veinticinco horas | ◆◆◆◆◇ | zonas horarias, AT TIME ZONE, date_trunc, definir el día antes de agrupar | Zonas horarias: guarda UTC, muestra local |
| 6 | Los que ya no están | ◆◆◆◆◆ | sesgo de supervivencia, universo histórico, join con vigencia, media de medias | El sesgo de supervivencia está en el JOIN |
| Nº | Caso | Dificultad | Técnicas | Trampa |
|---|---|---|---|---|
| 1 | La noche de marzo | ◆◆◆◆◇ | ventanas temporales, JOIN entre tablas sin clave, subconsulta como referencia, strftime | |
| 2 | El efectivo | ◆◆◆◆◆ | JOIN por importe y ventana de fechas, INTERVAL, GROUP BY con HAVING, cadena caja → portador → cuenta | |
| 4 | El peso del Anacleta | ◆◆◆◆◆ | JOIN por fecha con tolerancia, agregación por escala, HAVING contra una subconsulta, varias CTE en cadena | |
| 5 | Las tarjetas | ◆◆◆◆◆ | ventana LAG, self-join temporal, date_diff, JOIN por fecha con tolerancia | |
| 8 | La 88-C | ◆◆◆◆◆ | varias CTE en una consulta, agregados condicionales, HAVING contra una subconsulta, una fila con toda la verdad |
El profesor pide un código de grupo y recibe un enlace. Ese enlace abre el juego completo en el navegador de cada alumno: sin cuentas, sin instalar nada, funciona en las computadoras del laboratorio de la escuela.
El progreso de cada alumno se guarda solo en ese navegador. Si un alumno cambia de equipo, puede copiar su progreso como texto desde Ajustes → Progreso (botón «Copiar») y pegarlo en el otro equipo (botón «Pegar…»); el juego lo funde con lo que ya hubiera ahí, quedándose con el caso más avanzado de los dos.
La versión de aula, el juego que abre el enlace del código de grupo, no tiene cuentas, no pide datos al alumno, no tiene anuncios y no lleva analítica.
Esta página pública que estás leyendo es distinta: cuenta visitas con Cloudflare Web Analytics, sin cookies.
No medimos cuánto tarda un alumno ni cuánto aprende, todavía no. Los casos 0 a 4 son cortos. Los de dificultad 4 y 5 pueden llevarse una sesión entera. Sin medir todavía.
Escribe desde tu correo institucional con el curso, la institución, el número aproximado de alumnos y las fechas del semestre.
Escribe a christianvadillo@hotmail.com. Gratis para el aula.
Un plan de clase completo, con tres niveles y preguntas para la puesta en común. Imprimible. Guía de clase de 50 minutos →
Los errores que esconden los casos, cada uno en su página: qué falla, un SQL mínimo que lo reproduce, la versión correcta y por qué.
El primer caso se juega gratis en el navegador, sin cuenta.
Jugar el caso 1 gratis →