Guía completa de Ghost in the SQL Data: las 9 soluciones de casos y respuestas SQL

Guía completa de Ghost in the SQL Data con respuestas SQL para los 9 casos y 18 puntos de control, desde el tutorial del incendio escolar hasta el puzle del Elixir V.

Ghost in the SQL Data es un juego de detectives en el que resuelves crímenes escribiendo SQL real contra los registros de casos de París. Esta guía de Ghost in the SQL Data cubre los nueve casos y los 18 puntos de control, para que veas la lógica detrás de cada respuesta en lugar de limitarte a copiar una consulta. Si te has atascado en un solo punto de control o quieres el conjunto completo de soluciones, esta guía de Ghost in the SQL Data te ofrece tanto el razonamiento como el SQL exacto.

Cómo funciona Ghost in the SQL Data

El juego tiene dos modos. El Tutorial sigue el incendio del colegio Jean Moulin a lo largo de tres casos vinculados (1.1–1.3), donde cada pregunta resuelta se convierte en la preparación de la siguiente. Los Casos Independientes te entregan solo el informe y el tablero de pruebas, poniendo a prueba si puedes construir una consulta sin que te lleven de la mano. Los casos intermedios y avanzados se desbloquean tras superar los de principiante.

ElementoDetalle
Casos totales9 (3 de tutorial + 6 independientes)
Puntos de control totales18
Tipos de consulta permitidosSELECT y WITH de solo lectura
Sistema de pistasPor etapas: Pista → Pista 1 → Pista 2 → Pista 3 (la respuesta)
VerificaciónEl botón "Verify" compara tus filas de resultado con la respuesta esperada
PlataformasWindows y Mac (Steam)
Precio1.350 yenes (10 % de descuento de lanzamiento hasta el 12 de noviembre)

El tutorial usa una pantalla de "Desk": las notas del caso y la forma del resultado esperado a la izquierda, tu editor SQL a la derecha, y una cuadrícula de resultados debajo que puede alternar entre vistas de tabla, barras, líneas, gráfico circular y KPI. Los casos independientes usan un "Investigation Board" donde se fijan fotos, declaraciones de testigos, mapas y extractos de tablas. Activas y desactivas los paneles Case Files y Query Console con botones en la parte superior.

Tres reglas rigen cada puzle:

  • Las respuestas son filas de resultado. El panel de resultado esperado te indica cuántas filas y qué columnas necesitas.
  • Las palabras de condición viven en las pruebas. Fechas, horas, nombres de salas, marcas y números de placa aparecen resaltados en los archivos del caso y van directamente a las cláusulas WHERE.
  • Filtra una condición a la vez. Empieza con SELECT *, luego añade la fecha, después la ubicación, y observa cómo cae el recuento de filas.

Los valores permanecen en inglés exactamente como aparecen en las tablas. Las horas usan el formato '21:12' y se pueden comparar con < y >. Las fechas usan '2025-10-14'.

Casos del tutorial: el incendio escolar (1.1–1.3)

La noche del 14 de octubre, el Ala de Ciencias del colegio Jean Moulin se incendió. El tutorial rastrea la llamada, la sala de la que provino y el autor de la llamada.

Caso 1.1: Introducción

La tabla dispatch_log contiene 2.400 llamadas de emergencia de un año completo. Tu objetivo es el único informe de incendio registrado antes de las 21:12, el momento en que el primer testigo vio llamas.

PasoCondición añadidaFilas devueltas
1Ninguna (SELECT *)2.400
2on_date = '2025-10-14'16
3Tipo de llamada, asunto, lugar, hora1

La consulta final:

SELECT * FROM dispatch_log
WHERE on_date = '2025-10-14'
  AND kind = 'Phone Call'
  AND subject = 'Fire'
  AND site = 'College Jean Moulin'
  AND at_time < '21:12';

La respuesta es una llamada de las 20:58 desde LINE 4417. Omite la condición del lugar y obtendrás dos filas, porque un incendio en el Rialto Cinema se reportó a las 19:32 esa misma noche.

Caso 1.2: JOIN

El registro de la compañía telefónica line_register (30 filas) asigna cada línea a un abonado y una sala. dispatch_log.source coincide con line_register.line.

Unir las dos tablas el 14 de octubre devuelve 9 filas en lugar de 16, porque las llamadas desde teléfonos públicos, paneles de alarma y coches patrulla no tienen entrada en el registro y quedan fuera del join. LINE 4417 está registrada en tres salas según la franja horaria:

SalaHorario
Main Office08:00-18:00
Lodge18:00-22:00
Flat22:00-08:00

A las 20:58 la llamada vino de la Lodge. La consulta:

SELECT room, at_time
FROM dispatch_log
JOIN line_register ON source = line
WHERE source = 'LINE 4417'
  AND on_date = '2025-10-14'
  AND hours = '18:00-22:00';

Caso 1.3: ORDER BY y LIMIT

La Lodge es la habitación del conserje. La tabla keycard_log (105 filas) registra los deslizamientos de placa. Para encontrar quién pasó por última vez por la Main Gate ese día, ordena de forma descendente y toma una fila:

SELECT holder, door, at_time
FROM keycard_log
WHERE on_date = '2025-10-14' AND door = 'Main Gate'
ORDER BY at_time DESC
LIMIT 1;

Esa es Ruth Abasi a las 21:19. Cambia la puerta a Lodge y añade at_time < '20:58' y obtendrás a Victor Pell a las 20:44. Su registro de movimientos muestra Boiler Room a las 20:35, Science Wing a las 20:41, y luego Lodge — contradiciendo su declaración. La fila de respuesta es su deslizamiento en Boiler Room:

SELECT holder, door, on_date, at_time FROM keycard_log
WHERE holder = 'Victor Pell' AND on_date = '2025-10-14' AND door = 'Boiler Room';

Soluciones de los casos independientes

The Blue House (Principiante)

Cinco casas en Villa Godin fueron pintadas de azul durante la noche, dejando una lata de Brikoko Blue Paint. shop_sales contiene 1.240 transacciones de ferretería; loyalty_cards asigna 260 tarjetas a propietarios y barrios.

Filtrar solo por marca y artículo da tres titulares de tarjeta. Añadir el barrio lo reduce a uno:

SELECT DISTINCT loyalty_cards.card, holder, house, neighbourhood
FROM shop_sales
JOIN loyalty_cards ON shop_sales.card = loyalty_cards.card
WHERE item = 'Blue Paint' AND brand = 'Brikoko'
  AND neighbourhood = 'Saint Fargeau';

La respuesta es Miles Greaves, casa número 7. Quita la marca y los compradores de pintura azul Dulvo y Greenway inundan los resultados.

The Hospital Stalker (Principiante)

Tres enfermeras fueron atacadas en el Hopital Lamarck justo después de salir de la Drug Reserve. door_log registra los deslizamientos de placa solo de entrada; staff_badges contiene 20 titulares de placas y sus roles.

DíaSalaVíctimaEntrada del sospechoso
LunesSupply Room—Colin Marsh
MiércolesWaste Room—Colin Marsh
JuevesLoading BayGrace Mensah 16:05Colin Marsh 16:09

La fila de respuesta viene de la tabla de placas:

SELECT * FROM staff_badges WHERE holder = 'Colin Marsh';

El segundo punto de control pregunta quién es el siguiente. Solo las enfermeras conocen el código de la Drug Reserve, así que haces un self-join de door_log para encontrar a qué enfermera siguió Colin en un margen de tres minutos el viernes. El resultado es Owen Clarke:

SELECT * FROM staff_badges WHERE holder = 'Owen Clarke';

The Next Target (Intermedio)

Seis bancos de París fueron robados desde junio. La tabla banks cubre 100 sucursales con un security_score asignado por la policía. Ordena las sucursales robadas por fecha y aparece un patrón: cada golpe tenía una cámara acorazada, Okonjo Insurance, al menos 110.000 en efectivo, y una puntuación de seguridad que subía de dos en dos — 20, 22, 24, 26, 28, 30. El séptimo objetivo debería tener 32.

SELECT bank, bank_id, sector, security_score, vault_cash FROM banks
WHERE status = 'Open' AND kind = 'Vault'
  AND insurer = 'Okonjo Insurance' AND vault_cash >= 110000
ORDER BY security_score;

Solo Civique Mozart (B240) está en 32.

The Orsay Crown (Intermedio)

Una corona ceremonial desapareció de la Orsay Reserve el 19 de noviembre. badge_passages registra tanto las direcciones de entrada como de salida; badge_holders cubre 224 placas.

El punto de control 1 busca placas en la Reserve entre las 17:30 (cuando se guardó la corona) y las 18:40 (cuando se encontró la vitrina vacía). Solo aparece el registrador Etienne Vasseur (B-0218) — pero denunció el robo de su placa mientras estaba enfermo en los Restrooms.

El punto de control 2 encuentra al ladrón contando entradas frente a salidas por placa:

SELECT h.last_name, h.first_name, h.badge_id, h.role
FROM badge_holders h
JOIN badge_passages p ON p.badge_id = h.badge_id
WHERE p.room = 'Restrooms'
GROUP BY h.badge_id
HAVING SUM(p.direction = 'in') > SUM(p.direction = 'out');

La respuesta es Hugo Delorme, placa de Visitante B-0109, que entró en los Restrooms a las 17:33 y nunca salió con su propia placa.

The Nameless Ticket (Intermedio)

Una anciana fue atropellada en la rue Ramponeau, dejando un billete de 10 viajes no registrado C-88291. supports agrupa las tarjetas compradas en un mismo pago por payment_id; validations contiene dos meses de registros de tornos.

Primero, encuentra el pago: C-88291 pertenece al pago V-88410, que cubre 10 tarjetas compradas en efectivo en Gare du Nord el 28 de septiembre a las 07:12. Luego revisa las validaciones matutinas de esas tarjetas:

SELECT v.on_date, v.at_time, v.station, v.line, v.direction
FROM validations v JOIN supports s ON s.card_id = v.card_id
WHERE s.payment_id = 'V-88410' AND v.at_time < '09:00'
ORDER BY v.on_date, v.at_time;

El hombre entra en la M2 cada mañana y sale en la M13. El único intercambio entre esas líneas es Place de Clichy, así que escribes el nombre de la estación directamente:

SELECT 'Place de Clichy' AS kiosk;

Elixir V (Avanzado)

La botánica Odile Vernet quiere saber qué entró en el Elixir V, elaborado con tres flores. La tabla flowers contiene 52 especímenes analizados. Dos flores son frescas y una es seca, y la mezcla debe cumplir tres criterios: A > 22, ROUND(K, 2) = 29, y F entre 17 y 21. Las fórmulas están fijadas en el tablero, y los valores de la flor seca se multiplican por (1 - moisture).

Los criterios por sí solos dejan varias combinaciones. El cuaderno está fechado el 5 de julio y las tres flores florecieron en un invernadero sin calefacción, así que restringes las estaciones a verano o todo el año:

SELECT a.common_name AS flower_a, b.common_name AS flower_b, c.common_name AS flower_c
FROM flowers AS a, flowers AS b, flowers AS c
WHERE a.state = 'fresh' AND b.state = 'fresh' AND c.state = 'dried'
  AND 300 * (1.0 / a.dpph_ic50 + 1.0 / b.dpph_ic50 + (1 - c.moisture) / c.dpph_ic50) > 22
  AND ROUND(270 * (1.0 / a.nfkb_ic50 + 1.0 / b.nfkb_ic50 + (1 - c.moisture) / c.nfkb_ic50), 2) = 29
  AND (a.phenols_100g + b.phenols_100g + (1 - c.moisture) * c.phenols_100g)
      / (270 * (1.0 / a.nfkb_ic50 + 1.0 / b.nfkb_ic50 + (1 - c.moisture) / c.nfkb_ic50) + 1) BETWEEN 17 AND 21
  AND a.season IN ('summer', 'ALL') AND b.season IN ('summer', 'ALL') AND c.season IN ('summer', 'ALL')
LIMIT 1;

La respuesta es manzanilla alemana fresca, melisa fresca y lavanda verdadera seca.

Cinco técnicas que resuelven todos los casos

Estos patrones se repiten en todo el juego, y los informes de la comunidad confirman que cubren todos los puntos de control.

TécnicaCaso de usoSintaxis clave
Filtrado progresivoReducir 2.400 filas a 1WHERE con AND
Conciencia del JOINLas filas desaparecen cuando a una tabla le falta una coincidenciaJOIN ... ON
Último/anterior registro"Quién fue el último" o "justo antes"ORDER BY DESC + LIMIT 1
Self-join"Quién vino justo después"La misma tabla con dos alias
Recuento de entradas frente a salidas"Entró y nunca salió"GROUP BY + HAVING
  • Sospecha de filas faltantes tras un JOIN. En el Caso 1.2 las 16 llamadas se convirtieron en 9 filas porque las fuentes no registradas no tienen entrada en el registro. Lo mismo ocurre con los clientes en efectivo en The Blue House.
  • Incluye siempre la fecha con las condiciones de hora. Un at_time < '20:58' sin más coincide también con registros de otros días.
  • Usa alias repetidamente para la misma tabla. El caso del hospital usa door_log dos veces, una como m y otra como v, unidas por puerta y fecha coincidentes con una ventana de tres minutos.
  • Ordena antes de buscar patrones. El caso de los bancos no tiene la respuesta escrita en ningún sitio — la regla solo aparece una vez que ordenas por robbed_on.
  • Usa DISTINCT cuando los joins dupliquen filas. Un titular de tarjeta con varias compras de pintura aparecería de lo contrario varias veces.

Para repasar la sintaxis general de SQL, la referencia oficial de SQL SELECT de W3Schools cubre cada cláusula usada aquí.

Pistas, idioma y ajustes de calidad de vida

Las pistas se desbloquean en orden: Clue te dice dónde mirar, la Pista 1 explica con palabras, la Pista 2 da el esqueleto de la consulta, y la Pista 3 es la respuesta completa. No puedes saltarte pasos. La SQL Guide de la esquina superior derecha ofrece tarjetas por cláusula con ejemplos breves y resultados paso a paso.

El juego admite 10 idiomas, incluidos el japonés y el inglés. Los menús, archivos de casos, guías y pistas se traducen, pero los nombres de tablas, nombres de columnas, valores y nombres de personajes o lugares permanecen en inglés — que es exactamente lo que escribes en las consultas. Los ajustes incluyen opciones de visualización, tamaño del texto, modo oscuro, volumen de sonido y música, y un modo para streamers.

FAQ

¿Cuántos casos hay en Ghost in the SQL Data? Hay nueve casos: tres capítulos de tutorial sobre el incendio escolar y seis casos independientes, con un total de 18 puntos de control. Todos son resolubles con unas pocas líneas de SQL.

¿Necesito experiencia en SQL para completar esta guía de Ghost in the SQL Data? No. El tutorial enseña SELECT, WHERE, JOIN, ORDER BY y LIMIT desde cero. Los casos posteriores introducen GROUP BY, subconsultas y self-joins, pero las pistas por etapas te guían hasta cada respuesta.

¿Por qué mi JOIN devuelve menos filas de las esperadas? Los inner joins descartan las filas sin coincidencia en la segunda tabla. Las llamadas desde teléfonos públicos o las compras sin tarjeta de fidelidad simplemente desaparecen. Si el recuento parece incorrecto, comprueba qué valores existen solo en una tabla.

¿Puedo dañar los registros del caso con una consulta errónea? No. Solo se permiten sentencias SELECT y WITH de solo lectura, así que nada de lo que escribas puede alterar las pruebas.

¿Cómo respondo con un nombre o una estación en lugar de una fila de tabla? Envuelve el valor entre comillas simples y dale un alias de columna, como SELECT 'Place de Clichy' AS kiosk;. El botón Verify compara tus filas de salida con la forma esperada.

Con estas soluciones y técnicas, todos los casos de esta guía de Ghost in the SQL Data deberían resolverse en unas pocas consultas. Trabaja los filtros de uno en uno, vigila los recuentos de filas, y las deducciones se escriben solas.