Este ejercicio parte de una pregunta sencilla pero muy útil para practicar análisis de datos con SQL: ¿Qué instructores aparecen más veces en el Top 5 del ranking de cursos?
En este contexto, el ejercicio indica que la plataforma registra cursos, instructores y posiciones históricas en una tabla de rankings. Además, un mismo curso puede aparecer varias veces en distintos periodos, por lo que, en consecuencia, necesitamos consolidar toda esa información para medir el desempeño real. Dicho de otra manera, en resumen, necesitamos calcular un ranking de instructores usando SQL.
Paso 1 — Identificar las apariciones Top 5
Para resolver esto, este paso implica unir (hacer un join) las tablas instructors, courses y course_rankings, ya que cada una aporta una pieza distinta del rompecabezas. Una vez realizada esta unión, a continuación, filtraremos los registros donde therank <= 5, de manera que nos quedaremos con las apariciones “exitosas”.
Paso 2 — Contar apariciones por instructor
En este punto, agruparemos utilizando la columna instructor_id para consolidar todas las apariciones de cada instructor. Dado que un instructor puede tener varios cursos y, además, cada curso puede aparecer múltiples veces, este paso permite transformar filas dispersas en una métrica clara: cuántas veces sus cursos entraron al Top 5.
Paso 3 — Asignar ranking con DENSE_RANK
Una vez que tengamos las apariciones por instructor, ordenaremos el resultado por el conteo en orden descendente. A continuación, aplicaremos DENSE_RANK(), lo que permite asignar una posición a cada instructor según su desempeño.
¿Por qué DENSE_RANK() y no RANK()?
RANK()deja huecos: 1, 2, 2, 4DENSE_RANK()no deja huecos: 1, 2, 2, 3
Además, como buscamos identificar a los Top 3 instructores, es importante trabajar con rangos continuos, ya que esto evita que, ante un empate, se produzcan saltos en las posiciones.
Paso 4 — Filtrar solo los Top 3 instructores
Una vez que tenemos el ranking calculado, filtraremos con WHERE instructor_rank <= 3. De esta manera, obtenemos los tres niveles superiores, ya que se respetan los empates y se mantiene la lógica de un ranking continuo.
Respuesta al problema de ranking de instructores (con comentarios)
-- ============================================
-- EN: English
-- ES: Español
-- ============================================
-- CTE #1: Count how often each instructor appears in the Top-N
-- CTE #1: Contar cuántas veces cada instructor aparece en el Top-N
--
-- EN: We join instructors, courses, and course_rankings because each table
-- contributes a different piece of information. We filter only the rows
-- where the course reached a Top-5 position. Then we group by instructor
-- to consolidate all their high-ranking appearances.
--
-- ES: Unimos instructors, courses y course_rankings porque cada tabla aporta
-- una parte distinta de la información. Filtramos únicamente las filas
-- donde el curso alcanzó una posición dentro del Top 5. Luego agrupamos
-- por instructor para consolidar todas sus apariciones destacadas.
-- ============================================
WITH cte_instructor_top_counts AS (
SELECT
MAX(i.instructor_name) AS instructor_name,
-- EN: MAX() is used simply to retrieve the instructor name once per group.
-- ES: MAX() se usa solo para obtener el nombre del instructor una vez por grupo.
COUNT(1) AS cnt
-- EN: COUNT(1) counts all rows in the group. I prefer COUNT(1) over COUNT(*)
-- for stylistic reasons; both behave the same in modern engines.
-- ES: COUNT(1) cuenta todas las filas del grupo. Prefiero COUNT(1) sobre COUNT(*)
-- por estilo; ambos funcionan igual en motores modernos.
FROM instructors i
INNER JOIN courses c
ON i.instructor_id = c.instructor_id
-- EN: Connect each instructor to their courses.
-- ES: Conecta cada instructor con sus cursos.
INNER JOIN course_rankings cr
ON c.course_id = cr.course_id
-- EN: Connect each course to its ranking history.
-- ES: Conecta cada curso con su historial de rankings.
WHERE cr.therank <= 5
-- EN: Keep only Top-5 appearances.
-- ES: Mantener solo las apariciones dentro del Top 5.
GROUP BY i.instructor_id
-- EN: Group by instructor so we can count their total Top-5 appearances.
-- ES: Agrupar por instructor para contar sus apariciones totales en el Top 5.
),
-- ============================================
-- CTE #2: Rank instructors by number of Top-5 appearances
-- CTE #2: Asignar ranking a los instructores según sus apariciones Top-5
--
-- EN: We apply DENSE_RANK() so that ties share the same rank and no gaps appear.
-- This is important because we want a clean Top 3 even if ties occur.
--
-- ES: Aplicamos DENSE_RANK() para que los empates compartan el mismo rango
-- y no existan saltos. Esto es importante porque queremos un Top 3 limpio
-- incluso si hay empates.
-- ============================================
cte_ranked_instructors AS (
SELECT
instructor_name,
DENSE_RANK() OVER (ORDER BY cnt DESC) AS instructor_rank,
-- EN: Higher counts get better ranks (1 = best).
-- ES: Los conteos más altos obtienen mejores rangos (1 = mejor).
cnt
-- EN: Keep the count for reference.
-- ES: Mantener el conteo para referencia.
FROM cte_instructor_top_counts
)
-- ============================================
-- Final Query: Return the Top 3 instructors
-- Consulta Final: Devolver los Top 3 instructores
--
-- EN: We filter by instructor_rank <= 3 to get the top three levels,
-- respecting ties and ensuring continuity in ranking.
--
-- ES: Filtramos instructor_rank <= 3 para obtener los tres niveles superiores,
-- respetando empates y manteniendo continuidad en el ranking.
-- ============================================
SELECT *
FROM cte_ranked_instructors
WHERE instructor_rank <= 3
ORDER BY instructor_rank;
Puede descargar la respuesta de este ejercicio de ranking de instructores desde este repositorio.
Respuesta al problema de ranking de instructores (sin comentarios)
WITH cte_instructor_top_counts AS (
SELECT
MAX(i.instructor_name) AS instructor_name,
COUNT(1) AS cnt
FROM instructors i
INNER JOIN courses c ON i.instructor_id = c.instructor_id
INNER JOIN course_rankings cr ON c.course_id = cr.course_id
WHERE cr.therank <= 5
GROUP BY i.instructor_id
),
cte_ranked_instructors AS (
SELECT
instructor_name,
DENSE_RANK() OVER (ORDER BY cnt DESC) AS instructor_rank,
cnt
FROM cte_instructor_top_counts
)
SELECT *
FROM cte_ranked_instructors
WHERE instructor_rank <= 3
ORDER BY instructor_rank;
Imagen de Robin Higgins – Pixabay

