Las ciudades están en ruinas. Las carreteras, bloqueadas por coches abandonados. El olor a pólvora y carne podrida se mezcla en el aire mientras hordas de mutantes se extienden sin control. Los pocos refugios que aún se mantienen en pie dependen de un único recurso para resistir un día más: los datos de nuestra base de datos SurvivalDB. Y ahí entramos nosotros, con un SQL Server medio polvoriento pero funcionando como un reloj.
En este primer episodio de nuestra serie para aprender a analizar datos en SQL no vas a encontrar dashboards color pastel ni entornos de BI con animaciones, el mundo se acaba y no hay tiempo para eso. Solo tenemos datos crudos, queries eficientes y la urgencia de sobrevivir. Hoy vamos a plantear una serie de ejercicios básicos que te permitirán dominar SELECT, WHERE y JOIN, mientras ayudamos a los últimos supervivientes a organizar sus suministros, identificar amenazas y evitar convertirse en croquetas mutantes.
El escenario: SurvivalDB, el corazón de la resistencia
En nuestro mundo postapocalíptico, la base de datos SurvivalDB es el último bastión de la civilización. Contiene cuatro tablas esenciales que almacenan la información crítica para la resistencia:
- RefugeSupplies: el inventario de cada refugio, incluyendo comida, agua, armas y ubicación geográfica (latitud y longitud). Saber qué refugio tiene recursos y cuál se muere de hambre es la diferencia entre enviar ayuda o enterrar cadáveres.
- SurvivorStats: registra la población de cada refugio y el número de infectados. Porque nada genera más pánico que un refugio lleno de supervivientes a punto de convertirse en mutantes.
- MutantSightings: almacena los avistamientos de hordas de mutantes con fecha y localización. Analizar estos datos permite anticipar ataques y planificar rutas seguras para los supervivientes.
- EvacuationRoutes: describe las rutas de evacuación posibles entre refugios, indicando desde qué refugio se parte y a cuál se llega. Es vital para planificar la huida cuando la defensa ya no es una opción y sólo queda correr.
Te dejo el script para que crees tú mismo la base de datos, las tablas y los datos que vamos a usar en los ejercicios.
CREATE DATABASE SurvivalDB;
GO
USE SurvivalDB;
GO
-- Eliminar tablas si existen para poder repetir el script sin errores
IF OBJECT_ID('EvacuationRoutes', 'U') IS NOT NULL DROP TABLE EvacuationRoutes;
IF OBJECT_ID('MutantSightings', 'U') IS NOT NULL DROP TABLE MutantSightings;
IF OBJECT_ID('SurvivorStats', 'U') IS NOT NULL DROP TABLE SurvivorStats;
IF OBJECT_ID('RefugeSupplies', 'U') IS NOT NULL DROP TABLE RefugeSupplies;
GO
-- ================================================
-- TABLA RefugeSupplies: Inventario de los refugios
-- ================================================
CREATE TABLE RefugeSupplies (
RefugeID INT PRIMARY KEY,
FoodRations INT,
WaterLiters INT,
Weapons INT,
Latitude FLOAT,
Longitude FLOAT
);
-- Insertar datos de prueba en RefugeSupplies
INSERT INTO RefugeSupplies VALUES
(1, 5, 30, 2, 40.0, -74.0),
(2, 15, 80, 10, 40.5, -74.5),
(3, 20, 60, 55, 39.5, -73.5),
(4, 8, 45, 18, 40.2, -74.2),
(5, 25, 90, 60, 40.8, -74.8),
(6, 18, 70, 30, 42.0, -76.0),
(7, 12, 55, 15, 38.0, -72.5),
(8, 22, 85, 45, 39.7, -73.8);
-- ================================================
-- TABLA SurvivorStats: Población e infectados
-- ================================================
CREATE TABLE SurvivorStats (
RefugeID INT PRIMARY KEY,
Population INT,
Infected INT
);
-- Insertar datos de prueba en SurvivorStats
INSERT INTO SurvivorStats VALUES
(1, 60, 7),
(2, 40, 1),
(3, 100, 3),
(4, 55, 6),
(5, 80, 2),
(6,56,6),
(7,62,1),
(8,74,3);
-- ================================================
-- TABLA MutantSightings: Avistamientos mutantes
-- ================================================
CREATE TABLE MutantSightings (
SightingID INT IDENTITY PRIMARY KEY,
SightingDate DATETIME,
Latitude FLOAT,
Longitude FLOAT
);
-- Insertar datos de prueba en MutantSightings (últimos 7 días)
INSERT INTO MutantSightings (SightingDate, Latitude, Longitude) VALUES
(DATEADD(DAY, -6, GETDATE()), 40.1, -74.1),
(DATEADD(DAY, -5, GETDATE()), 40.2, -74.2),
(DATEADD(DAY, -5, GETDATE()), 40.0, -74.0),
(DATEADD(DAY, -3, GETDATE()), 40.4, -74.4),
(DATEADD(DAY, -2, GETDATE()), 40.2, -74.2),
(DATEADD(DAY, -1, GETDATE()), 40.8, -74.8),
(GETDATE(), 39.6, -73.6);
-- ================================================
-- TABLA EvacuationRoutes: Rutas entre refugios
-- ================================================
CREATE TABLE EvacuationRoutes (
FromRefugeID INT,
ToRefugeID INT
);
-- Insertar datos de prueba en EvacuationRoutes
INSERT INTO EvacuationRoutes VALUES
(1, 3),
(3, 2),
(2, 4),
(4, 5),
(5, 7),
(7, 6),
(6, 8);

Ejercicios: cada consulta es un capítulo en la lucha por la supervivencia
El destino de los supervivientes depende de cómo consultemos estos datos. Un SELECT rápido puede significar reforzar un refugio a tiempo; un SELECT lento puede significar que ya es demasiado tarde. Comete cualquier error en tus consultas y podrías enviar suministros al refugio equivocado o ignorar un refugio al borde del colapso.
Ejercicio 1: Localiza los refugios al borde del colapso
Tras semanas sin recibir suministros, varios refugios podrían quedarse sin comida ni agua en cualquier momento. Si caen estos refugios, los supervivientes saldrán huyendo y propagarán el caos… o algo peor.
Tu misión: listar los refugios con menos de 10 raciones de comida o menos de 50 litros de agua. Tenemos que conocer el RefugeID, FoodRations y WaterLiters, ordenados de menor a mayor por FoodRations. Al ser el primero este será el único ejercicio con respuesta incluida como ejemplo.
SELECT RefugeID, FoodRations, WaterLiters
FROM RefugeSupplies
WHERE FoodRations < 10 OR WaterLiters < 50
ORDER BY FoodRations ASC;
Ejercicio 2: Identifica a los refugios mejor armados
Tras localizar los refugios en situación crítica, el Consejo necesita saber quiénes pueden apoyarlos. Los refugios con más armas son los únicos capaces de enviar ayuda o resistir un asedio prolongado.
Tu misión: mostrar los cinco refugios con mayor número de armas (Weapons), mostrando también RefugeID. Piensa cómo limitar los resultados para centrarte en los más fuertes.
Pista: Ordena tus datos de forma que los primeros sean los más peligrosos… o los más protegidos.
Ejercicio 3: Define la zona caliente del mapa
Los exploradores acaban de interceptar señales de radio que indican grandes movimientos de hordas entre las latitudes 39 y 41 y longitudes -75 y -73. Hay que comprobar si los refugios críticos o mejor armados están dentro de esa zona de peligro inminente.
Tu misión: listar los refugios ubicados en ese rango, mostrando RefugeID, Latitude y Longitude.
Pista: Dos coordenadas definen un área. ¿Cómo filtrarías para quedarte solo con los refugios dentro de esa caja imaginaria?
Ejercicio 4: Conoce a los supervivientes que defiendes
La información reunida hasta ahora es valiosa, pero incompleta. Necesitamos saber cuántos habitantes hay en cada refugio para calcular si tienen suficiente comida, agua y armas para sobrevivir. Sin estos datos combinados, cualquier estrategia será un tiro en la oscuridad.
Tu misión: combinar RefugeSupplies y SurvivorStats para mostrar RefugeID, Population, FoodRations y Weapons de cada refugio.
Pista: La información de suministros y la población viven en tablas distintas, pero tienen algo en común: el refugio.
Ejercicio 5: Identifica tragedias inminentes
El análisis anterior revela un peligro alarmante, algunos refugios tienen mucha gente pero apenas armas. Si un mutante llega, la masacre será inmediata y el caos se extenderá a otros refugios.
Tu misión: encontrar los refugios que tienen menos de 5 armas y más de 50 supervivientes. Estas son las prioridades absolutas para enviar refuerzos antes de que el desastre sea irreversible.
Pista: Para detectar refugios sobrepoblados y mal armados, debes comparar datos que no están en la misma tabla. ¿Cómo unirlos y luego aplicar las condiciones?
Consejo de veterano
En producción, la diferencia entre una consulta optimizada y una chapuza es la misma que entre un refugio reforzado y uno que se desmorona al primer ataque. Indexa, revisa planes de ejecución y parametriza: no estamos jugando, estamos sobreviviendo.
¿Quieres las respuestas?
Estoy preparando un vídeo en el canal de YouTube donde resolveremos paso a paso estos ejercicios y explicaremos cada detalle para que no sólo los copies, sino que los entiendas. Eso sí, tendrás que esperar a la semana que viene, mientras tanto intenta resolver estos ejercicios por tu cuenta para practicar y deja en comentarios tus respuestas.
Próximamente…
En el siguiente episodio subiremos la dificultad: cálculos de tasas de infección, clasificaciones y agrupaciones para decidir a quién ayudar primero. Porque en un mundo arrasado por mutantes, saber sumar y agrupar correctamente puede ser lo que te salve.


Me encanto el ejercicio 4 jajaja no se que te fumaste para este post..!!!
— Ejercicio 2: Identifica a los refugios mejor armados
SELECT TOP (5) R.RefugeID, R.Weapons
FROM SurvivalDB.dbo.RefugeSupplies AS R
WHERE R.Weapons > 0
ORDER BY R.Weapons DESC;
GO
— Ejercicio 3: Define la zona caliente del mapa
SELECT R.RefugeID, R.Latitude, R.Longitude
FROM SurvivalDB.dbo.RefugeSupplies AS R
WHERE (R.Latitude BETWEEN 39 AND 41) AND (R.Longitude BETWEEN -75 AND -73);
GO
— Ejercicio 4: Conoce a los supervivientes que defiendes
SELECT R.RefugeID, S.Population, R.FoodRations, R.WaterLiters, R.Weapons
FROM SurvivalDB.dbo.RefugeSupplies AS R
INNER JOIN SurvivalDB.dbo.SurvivorStats AS S ON (S.RefugeID=R.RefugeID);
GO
— Ejercicio 5: Identifica tragedias inminentes
SELECT R.RefugeID, S.Population, R.FoodRations, R.WaterLiters, R.Weapons
FROM SurvivalDB.dbo.RefugeSupplies AS R
INNER JOIN SurvivalDB.dbo.SurvivorStats AS S ON (S.RefugeID=R.RefugeID)
WHERE R.Weapons 50;
GO
— Ejercicio 5: Identifica tragedias inminentes
SELECT R.RefugeID, S.Population, R.FoodRations, R.WaterLiters, R.Weapons
FROM SurvivalDB.dbo.RefugeSupplies AS R
INNER JOIN SurvivalDB.dbo.SurvivorStats AS S ON (S.RefugeID=R.RefugeID)
WHERE R.Weapons 50;
No sé por qué los pega mal…. saludos.
Mejor les comparto por acá mi aporte, saludos: https://pastebin.com/4qf7S9Yr
— Ejercicio 1: Localiza los refugios al borde del colapso
Select RefugeID, FoodRations, WaterLiters
from [dbo].[RefugeSupplies]
where FoodRations<10 or WaterLiters= 39 and Latitude =-75 and Longitude<=-73)
–Ejercicio 4: Conoce a los supervivientes que defiendes
SELECT RS.RefugeID, Population, RS.FoodRations, RS.WaterLiters, RS.Weapons
from [dbo].[RefugeSupplies] as RS
inner join SurvivorStats as SS ON RS.RefugeID=SS.RefugeID
–Ejercicio 5: Identifica tragedias inminentes
SELECT RS.RefugeID, Population, RS.FoodRations, RS.WaterLiters, RS.Weapons
from [dbo].[RefugeSupplies] as RS
inner join SurvivorStats as SS ON RS.RefugeID=SS.RefugeID
where RS.Weapons 50
Interesante conversación sobre qué funciona mejor: beetwen o ><?
Ejercicio 1:
SELECT RefugeID, FoodRations, WaterLiters
FROM RefugeSupplies
WHERE FoodRations < 10 OR WaterLiters < 50
ORDER BY FoodRations ASC;
Ejercicio 2:
SELECT TOP 5 RefugeID, Weapons
FROM RefugeSupplies
ORDER BY Weapons DESC;
Ejercicio 3:
SELECT RefugeID, Latitude, Longitude
FROM RefugeSupplies
WHERE Latitude BETWEEN 39 AND 41
AND Longitude BETWEEN -75 AND -73;
Ejercicio 4:
SELECT
rs.RefugeID,
ss.Population,
rs.FoodRations,
rs.Weapons
FROM RefugeSupplies rs
JOIN SurvivorStats ss
ON rs.RefugeID = ss.RefugeID;
Ejercicio 5:
SELECT
rs.RefugeID,
ss.Population,
rs.Weapons
FROM RefugeSupplies rs
JOIN SurvivorStats ss
ON rs.RefugeID = ss.RefugeID
WHERE rs.Weapons 50;
Roberto me encanto este Reto.
Parte 1
Ejercicio 1
SELECT RefugeID, FoodRations, WaterLiters
FROM RefugeSupplies
WHERE FoodRations < 10 OR WaterLiters < 50
ORDER BY FoodRations ASC;
Ejercicio 2:
SELECT TOP 5 RefugeID, Weapons
FROM RefugeSupplies
ORDER BY Weapons DESC;
Ejercicio 3
SELECT RefugeID, Latitude, Longitude
FROM RefugeSupplies
WHERE Latitude BETWEEN 39 AND 41
AND Longitude BETWEEN -75 AND -73;
Ejercicio 4
SELECT
rs.RefugeID,
ss.Population,
rs.FoodRations,
rs.Weapons
FROM RefugeSupplies rs
JOIN SurvivorStats ss
ON rs.RefugeID = ss.RefugeID;
Ejercicio 5:
SELECT
rs.RefugeID,
ss.Population,
rs.Weapons
FROM RefugeSupplies rs
JOIN SurvivorStats ss
ON rs.RefugeID = ss.RefugeID
WHERE rs.Weapons 50;