Saltar al contenido principal

Actividad Progresiva SQL — Subiendo de Nivel

Esta actividad fue creada por Robinson Andres Cortes

En esta actividad explorarás consultas SQL a través de un conjunto de ejercicios de investigación. Intenta completar la actividad usando únicamente W3Schools, w3resource o SQLhabit como referencia.

Copia y pega el código proporcionado en tu DBMS de SQL preferido. Aunque los ejercicios funcionan con cualquier motor SQL, la solución de ejemplo utiliza MySQL.

No repetimos consultas que hagan exactamente lo mismo.
Cada paso añade una capa nueva de razonamiento.

Cuando alguien termina el Nivel 5 sin copiar, ya no está aprendiendo SQL.
Está aprendiendo a pensar en datos.


Nivel 1 — Fundamentos (Exploración básica)

  1. Listar todos los usuarios.

    Verificar si estoy en lo correcto

    En este ejercicio, necesitamos seleccionar todos los datos de la tabla en la base de datos que creamos. En este caso, la tabla se llama users.
    En SQL del mundo real, esta solución no difiere mucho de lo que verás en la práctica. El concepto clave aquí es que el operador * significa todas las columnas.

    Con esto en mente, aquí está la solución:

    SELECT * FROM users
  2. Mostrar solo first_name, last_name y email.

    Revelar la verdad

    En este ejercicio, continuamos con la misma lógica del anterior. El único cambio son las columnas seleccionadas.
    En lugar de seleccionar todas las columnas (*), ahora solo necesitamos obtener first_name, last_name y email.

    Con esto en mente, aquí está la solución:

    SELECT first_name, last_name, email FROM users
  3. Filtrar usuarios cuyo role sea 'admin'.

    Muéstrame la magia

    En este ejercicio, introducimos otro concepto de SQL llamado WHERE.
    Esta es una sentencia condicional que filtra los datos: solo se mostrarán las filas que cumplan con la condición dada:

    SELECT * FROM users WHERE role = 'admin'
  4. Filtrar usuarios con document_type = 'CC'.

    Momento de la verdad

    Este sigue el ejercicio anterior, pero ahora no estamos preguntando por el role.
    En su lugar, estamos buscando el document_type:

    SELECT * FROM users WHERE document_type = 'CC'
  5. Mostrar usuarios mayores de 18 años (calcular la edad desde birth_date).

    ¿Lo hice bien?

    Para resolver este reto, necesitamos introducir la función TIMESTAMPDIFF().
    En MySQL, TIMESTAMPDIFF() es una función poderosa que se utiliza para calcular la diferencia entre dos valores DATE o DATETIME.

    En este caso, convertimos birth_date a años comparándolo con la fecha actual, y luego verificamos si el usuario es mayor de 18 años.

    El ejercicio podría verse así:

    SELECT * FROM users WHERE TIMESTAMPDIFF(YEAR, birth_date , CURDATE()) > 18

    Más información sobre TIMESTAMPDIFF() aquí

  6. Mostrar usuarios cuyo ingreso sea mayor a 5,000,000.

    Haz clic para spoilers

    Siguiendo la misma lógica del ejercicio anterior, podemos usar el símbolo > (mayor que).
    Debemos asegurarnos de que monthly_income sea mayor que 5000000.

    Con esto en mente, aquí está la solución:

    SELECT * FROM users WHERE monthly_income > 5000000	    
  7. Mostrar usuarios cuyo nombre comience con "A".

    Veamos…

    Para resolver este ejercicio, debo presentarte un nuevo concepto llamado el operador LIKE.
    El operador LIKE se utiliza en una cláusula WHERE para buscar un patrón específico en una columna.
    Para devolver registros que comiencen con una letra o frase específica, se agrega el % al final de la letra o frase.

    El ejercicio podría verse así:

    SELECT * FROM users WHERE first_name like 'a%'	    

    Más información sobre el operador LIKE aquí

  8. Mostrar usuarios que no tengan company.

    Clic arriesgado

    Para resolver este reto, primero debemos entender que un usuario sin empresa tiene company = NULL.

    Para esto, introducimos un nuevo concepto de SQL: el operador IS.
    El operador IS se utiliza para comparar un valor con NULL o con valores booleanos (TRUE, FALSE). Es especialmente importante porque NULL no se puede comparar usando el operador =.

    Con esto en mente, aquí está la solución:

    SELECT * FROM users WHERE company IS NULL    

    Más información sobre el operador IS aquí

Aquí ya aprendiste SELECT, WHERE, operadores lógicos y NULL.


Nivel 2 — Combinación de condiciones

  1. Usuarios mayores de 25 años que sean 'employee'.

    Respuesta, por favor

    En este ejercicio introducimos algunos nuevos operadores de SQL. El primero es AND.

    El operador AND es un operador lógico que devuelve TRUE solo si ambas condiciones son TRUE.
    En este caso, la condición será TRUE si el usuario es mayor de 25 años y tiene empleo.

    Otro concepto importante es el operador NOT.
    El operador NOT también es un operador lógico que devuelve TRUE cuando una condición no se cumple.
    En este caso, si company no es NULL, la condición devolverá TRUE.

    Con esto en mente, aquí está la solución:

    SELECT * FROM users WHERE TIMESTAMPDIFF(YEAR, birth_date , CURDATE()) > 25 AND company IS NOT NULL   

    Más información sobre el operador AND aquí.
    Más información sobre el operador NOT aquí.

  2. Usuarios con 'CC' que estén activos.

    ¿Soy un genio?

    Siguiendo el ejercicio anterior, solo necesitamos verificar que document_type = 'CC' y is_active = 1:

    SELECT * FROM users WHERE document_type = 'CC' AND is_active = 1   
  3. Usuarios mayores de edad sin empleo.

    ¿O no…?

    Este ejercicio es similar al ejercicio 9, pero filtra usuarios mayores de 18 años, que es la mayoría de edad en mi país.

    SELECT * FROM users WHERE TIMESTAMPDIFF(YEAR, birth_date , CURDATE()) > 17 AND company IS NULL  
  4. Usuarios con empleo y con ingresos mayores a 3,000,000.

    Hora de confesar

    Primero, verificamos que el usuario tenga empleo.
    Esto significa que la columna company no debe ser NULL.

    Luego, filtramos los usuarios cuyo ingreso sea mayor a 3,000,000 usando el operador de comparación >.
    Ambas condiciones deben cumplirse para que el usuario aparezca en el resultado.

    Teniendo esto en cuenta, aquí está la solución:

    SELECT * FROM users WHERE company IS NOT NULL AND monthly_income > 3000000  
  5. Usuarios casados con al menos 1 hijo.

    Mostrar la respuesta

    Primero, verificamos el estado civil comparando la columna marital_status con el valor 'Casado'.
    Luego, nos aseguramos de que el usuario tenga al menos un hijo comprobando que children_count sea mayor o igual a 1.

    Ambas condiciones deben cumplirse para que el usuario sea incluido en el resultado.

    SELECT * FROM users WHERE marital_status = 'Casado' AND children_count >= 1  
  6. Usuarios entre 30 y 40 años.

    Prueba o dolor

    En este caso, primero verificamos que la edad del usuario sea mayor o igual a 30 y menor o igual a 40.
    Esto hace que el resultado esté entre los 30 y 40 años.

    SELECT * FROM users WHERE TIMESTAMPDIFF(YEAR, birth_date , CURDATE()) >= 30 AND TIMESTAMPDIFF(YEAR, birth_date , CURDATE()) <= 40 
  7. Usuarios 'admin' verificados mayores de 25 años.

    Júzgame

    Primero debemos asegurarnos de que el rol del usuario sea admin y que sea mayor de 25 años.

    SELECT * FROM users WHERE role = 'admin' AND TIMESTAMPDIFF(YEAR, birth_date , CURDATE()) > 25 

Aquí combinamos múltiples condiciones y lógica booleana.


Nivel 3 — Introducción a análisis (Agregaciones)

  1. Contar usuarios por role.

    Chequeo de realidad

    Para comenzar esta sección, necesitamos introducir algunos conceptos nuevos que nos ayudarán a resolver este reto.

    El primer concepto es la función COUNT().
    La función COUNT() se utiliza para contar el número de filas que coinciden con una condición específica.

    El segundo concepto es la sentencia GROUP BY.
    Esta agrupa filas que tienen los mismos valores en filas de resumen.

    El último concepto es la palabra clave AS, que se utiliza para renombrar una columna o tabla usando un alias.

    Suficiente teoría — pongamos las manos en el teclado.

    Primero, necesitamos hacer un SELECT de los datos que queremos analizar. En este caso, seleccionamos la columna role y el número de veces que aparece cada rol usando COUNT(role).
    En lugar de mostrar el nombre de columna por defecto COUNT(role), usamos la palabra clave AS para darle un alias más legible.

    Luego, especificamos la tabla donde están almacenados los datos y finalmente usamos GROUP BY para agrupar los resultados por rol.

    SELECT role, COUNT(role) AS Counting FROM users GROUP BY role 

    Más información sobre la función COUNT() aquí.
    Más información sobre la sentencia GROUP BY aquí.
    Más información sobre la palabra clave AS aquí.

  2. Contar usuarios por document_type.

    No te rías

    Este ejercicio es muy similar al anterior. En este caso, usamos document_type como el campo de agrupación.

    SELECT document_type, COUNT(document_type) AS Counting FROM users GROUP BY document_type 
  3. Contar cuántos usuarios están desempleados.

    Sé amable

    En este caso tomamos 'Unemployed' como un valor fijo y usamos COUNT(*) para contar todos los usuarios en la tabla users.
    Luego filtramos solo los usuarios WHERE company IS NULL, lo que significa que están desempleados.

    SELECT 'Unemployed', COUNT(*) AS Counting FROM users WHERE company IS NULL 
  4. Calcular el promedio general de ingresos.

    Haz clic con cuidado

    Para este ejercicio, necesitamos introducir un par de conceptos nuevos de SQL.

    El primero es la función AVG().
    La función AVG() devuelve el valor promedio de una columna numérica.

    El segundo y último concepto de esta sección es la función ROUND().
    La función ROUND() redondea un número a una cantidad específica de decimales.

    En este caso, queremos calcular el ingreso mensual promedio de todos los usuarios.
    Usamos la función AVG() para obtener el promedio y la función ROUND() para redondear el resultado a 0 decimales.

    Este es el resultado final:

    SELECT 'Average Income', ROUND(AVG(monthly_income ), 0) FROM users

    Más información sobre la función AVG() aquí.
    Más información sobre la función ROUND() aquí.

  5. Calcular el promedio de ingresos por role.

    La gran revelación

    Este ejercicio es muy similar al anterior, pero en este caso agrupamos los resultados usando GROUP BY role.

    SELECT role, ROUND(AVG(monthly_income ), 0) AS average_income FROM users GROUP BY role

Ahora ya no estás consultando individuos, estás leyendo patrones.


Nivel 4 — Pensamiento analítico

  1. Mostrar profesiones con más de 10 personas.

    ¿Estuve cerca?

    En este ejercicio reunimos varios conceptos. Primero, introducimos un nuevo tema de SQL llamado HAVING.

    La cláusula HAVING funciona de manera similar a WHERE, pero con una diferencia importante:
    la cláusula WHERE no puede usarse con funciones de agregación, mientras que HAVING sí.

    Nuestro objetivo es mostrar todas las profesiones de los usuarios, contar cuántos usuarios pertenecen a cada profesión, asignar un alias a ese conteo, agrupar los resultados por profesión y finalmente filtrar aquellas profesiones que tengan más de 10 usuarios.

    Con esto en mente, aquí está la solución:

    SELECT profession, COUNT(*) AS profession_count FROM users GROUP BY profession HAVING profession_count > 10

    Más información sobre HAVING aquí.

  2. Mostrar la ciudad con más usuarios.

    Respuesta desbloqueada

    En esta sección empieza lo divertido, porque ahora debemos usar algunos conceptos que son realmente útiles en el campo.

    El primer concepto que veremos se llama la palabra clave ORDER BY. Esta palabra clave se utiliza para ordenar los elementos de una forma específica, ya sea ascendente (ASC) o descendente (DESC); en este caso vamos a usar DESC.

    Otra herramienta importante es LIMIT. Esta cláusula limita los resultados a la cantidad que especifiquemos; en este caso solo necesitamos el primer resultado.

    Teniendo todo esto en cuenta, esta es la solución:

    SELECT city, COUNT(*) AS city_count FROM users GROUP BY city ORDER BY city_count DESC LIMIT 1

    Más información sobre la palabra clave ORDER BY aquí.
    Más información sobre LIMIT aquí.

  3. Comparar la cantidad de menores vs mayores de edad.

    Sin trampas

    Es momento de presentarles un nuevo concepto increíble: la función SUM().
    La función SUM() devuelve la suma de una columna numérica. Si dentro de la función hay una expresión booleana y esta devuelve TRUE, entonces suma 1.
    Si devuelve FALSE, entonces suma 0.

    En este caso se vería así:

    SELECT
    SUM(TIMESTAMPDIFF(YEAR, birth_date, CURDATE()) > 17) AS adults,
    SUM(TIMESTAMPDIFF(YEAR, birth_date, CURDATE()) < 18) AS minors
    FROM users

    Más información sobre la función SUM() aquí.

  4. Promedio de ingresos por ciudad, ordenado de mayor a menor.

    Vamos a descubrirlo

    Otro excelente ejercicio para practicar múltiples conceptos de SQL al mismo tiempo.

    En este ejercicio, primero calculamos el promedio de monthly_income para cada ciudad.
    Luego, redondeamos ese valor y le asignamos un alias.
    Después, agrupamos los resultados por ciudad y finalmente los ordenamos por monthly_income de forma descendente.

    Con todo esto en mente, aquí está la solución:

    SELECT city, ROUND(AVG(monthly_income )) AS income_city FROM users GROUP BY city ORDER BY income_city DESC
  5. Mostrar las 5 personas con mayor ingreso.

    Redoble de tambores…

    Si has completado los ejercicios anteriores en orden, este debería ser extremadamente fácil.

    Primero, seleccionamos las columnas first_name y monthly_income.
    Luego, ordenamos los resultados por monthly_income de forma descendente y limitamos la salida a los primeros 5 registros.

    Con eso en mente, aquí está la solución:

    SELECT first_name, monthly_income FROM `users` ORDER BY monthly_income DESC LIMIT 5

Aquí ya estás usando GROUP BY, ORDER BY, LIMIT y HAVING.


Nivel 5 — Nivel Ingeniero

  1. Clasificar usuarios como "Menor", "Adulto" o "Adulto mayor".

    Los dioses de las matemáticas deciden

    Ahora es momento de explorar una nueva condición llamada la expresión CASE.

    La expresión CASE evalúa condiciones y devuelve un valor cuando se cumple la primera condición (similar a una estructura if-then-else). Una vez que una condición es verdadera, deja de evaluarse y retorna el resultado. Si ninguna condición se cumple, devuelve el valor definido en la cláusula ELSE.

    Si no existe una parte ELSE y ninguna condición se cumple, el resultado será NULL.

    Con esto en mente, continuemos:

    SELECT first_name, 
    CASE
    WHEN TIMESTAMPDIFF(YEAR, birth_date, CURDATE()) < 18 THEN 'Minor'
    WHEN TIMESTAMPDIFF(YEAR, birth_date, CURDATE()) >= 18 AND TIMESTAMPDIFF(YEAR, birth_date, CURDATE()) < 65 THEN 'Adult'
    ELSE 'Senior'
    END AS age_group
    FROM users

    Más información sobre la expresión CASE aquí.

  2. Mostrar cuántos usuarios hay en cada una de las clasificaciones anteriores.

    La verdad duele

    Vamos a agrupar varios conceptos para resolver este ejercicio.

    Primero, necesitamos calcular el número total de usuarios que caen dentro de un rango de edad específico: 'Minor', 'Adult' o 'Senior'.

    Si un usuario coincide con una categoría determinada, sumamos 1 a ese grupo usando la función SUM(), y luego mostramos los totales finales para cada categoría.

    SELECT 
    SUM(TIMESTAMPDIFF(YEAR, birth_date, CURDATE()) < 18) AS 'Minor',
    SUM(TIMESTAMPDIFF(YEAR, birth_date, CURDATE()) >= 18 AND TIMESTAMPDIFF(YEAR, birth_date, CURDATE()) < 65) AS 'Adult',
    SUM(TIMESTAMPDIFF(YEAR, birth_date, CURDATE()) >= 65) AS 'Senior'
    FROM users
  3. Ranking de ingresos por ciudad.

    Verifica mi genialidad

    En este caso debemos hacer un SUM del monthly_income de la tabla users y agrupar el resultado usando GROUP BY city.
    Luego ordenamos con ORDER BY income en orden descendente para crear el ranking.

    Este es el resultado:

    SELECT city, SUM(monthly_income) AS income FROM users GROUP BY city ORDER BY income DESC
  4. Profesión con mayor ingreso promedio.

    Modo esperanza ACTIVADO

    Manos a la obra.

    Primero debemos calcular el AVG del monthly_income de todos los usuarios y agrupar el resultado por profession.
    Luego ordenamos con ORDER BY income en orden descendente.
    Finalmente, limitamos el resultado a 1 para obtener el ingreso promedio más alto:

    SELECT profession,
    ROUND(AVG(monthly_income),0) AS income
    FROM users
    GROUP BY profession
    ORDER BY income DESC
    LIMIT 1
  5. Mostrar usuarios cuyo ingreso esté por encima del promedio general.

    ¿Respuesta final?

    Y llegamos al último ejercicio. Me imagino que ya puedes estar cansado, pero no hay problema, vamos a terminarlo.

    Primero necesitamos obtener la información necesaria. En este caso, requerimos first_name y monthly_income de los usuarios WHERE su ingreso sea mayor que el AVG del monthly_income.

    Con eso, terminamos con:

    SELECT first_name, monthly_income AS income 
    FROM users
    WHERE income > (SELECT AVG(monthly_income) FROM users)