Cómo obtener el séptimo salario más alto de la tabla EMPLOYEES usando SQL

Una pregunta clásica en entrevistas técnicas de SQL, Oracle y bases de datos es:

¿Cómo obtener el séptimo salario más alto de una tabla de empleados?

Aunque parece una consulta sencilla, existen varias formas de resolverla. Además, hay una consideración importante: ¿qué sucede cuando varios empleados tienen el mismo salario?

En este artículo utilizaremos una tabla llamada EMPLOYEES con una columna llamada SALARY y veremos diferentes métodos para encontrar el séptimo salario más alto.


Tabla EMPLOYEES

Supongamos que tenemos los siguientes datos:

SELECT employee_id,
       first_name,
       last_name,
       salary
FROM employees;

Ejemplo:

EMPLOYEE_IDFIRST_NAMELAST_NAMESALARY
100StevenKing24000
101NeenaKochhar17000
102LexDe Haan17000
103AlexanderHunold9000
104BruceErnst6000
105DavidAustin4800

Nuestro objetivo será ordenar los salarios de mayor a menor y encontrar el que ocupa la posición número 7.


Método 1: utilizando DENSE_RANK()

Una de las mejores formas de resolver este problema es utilizando la función analítica:

DENSE_RANK()

La consulta sería:

SELECT employee_id,
       first_name,
       last_name,
       salary
FROM (
    SELECT employee_id,
           first_name,
           last_name,
           salary,
           DENSE_RANK() OVER (ORDER BY salary DESC) AS salary_rank
    FROM employees
)
WHERE salary_rank = 7;

¿Cómo funciona?

La parte importante es:

DENSE_RANK() OVER (ORDER BY salary DESC)

Primero SQL ordena los salarios de mayor a menor.

Después asigna una posición a cada salario.

Por ejemplo:

SALARY    RANK
------    ----
24000       1
17000       2
17000       2
14000       3
13500       4
12000       5
11000       6
10000       7

En este ejemplo, el séptimo salario más alto sería:

10000

La ventaja de DENSE_RANK() es que los salarios duplicados reciben la misma posición.

Por esta razón suele ser la solución más apropiada cuando hablamos del séptimo salario distinto más alto.


Obtener solamente el salario

Si únicamente queremos conocer el valor del séptimo salario más alto:

SELECT DISTINCT salary
FROM (
    SELECT salary,
           DENSE_RANK() OVER (ORDER BY salary DESC) AS salary_rank
    FROM employees
)
WHERE salary_rank = 7;

El resultado podría ser:

SALARY
------
10000

Método 2: utilizando DISTINCT

Otra solución muy sencilla consiste en obtener primero los salarios diferentes.

SELECT salary
FROM (
    SELECT DISTINCT salary
    FROM employees
    ORDER BY salary DESC
)
OFFSET 6 ROWS
FETCH NEXT 1 ROW ONLY;

La lógica es sencilla.

Si queremos encontrar el séptimo salario:

1 → salario más alto
2 → segundo
3 → tercero
4 → cuarto
5 → quinto
6 → sexto
7 → séptimo

Entonces debemos ignorar los primeros seis:

OFFSET 6 ROWS

y recuperar solamente uno:

FETCH NEXT 1 ROW ONLY

Esta sintaxis es especialmente cómoda en versiones modernas de bases de datos que soportan OFFSET y FETCH.


Método 3: usando ROW_NUMBER()

También podemos utilizar:

ROW_NUMBER()

Por ejemplo:

SELECT employee_id,
       first_name,
       last_name,
       salary
FROM (
    SELECT employee_id,
           first_name,
           last_name,
           salary,
           ROW_NUMBER() OVER (ORDER BY salary DESC) AS rn
    FROM employees
)
WHERE rn = 7;

Sin embargo, aquí existe una diferencia importante.

Supongamos que tenemos:

EMPLOYEE    SALARY
--------    ------
John        20000
Mary        18000
Peter       18000
Robert      17000

Con ROW_NUMBER() obtenemos:

SALARY     ROW_NUMBER
------     ----------
20000           1
18000           2
18000           3
17000           4

Los empleados que tienen el mismo salario reciben posiciones diferentes.

Por ello, ROW_NUMBER() encuentra el empleado que ocupa físicamente la séptima posición después de ordenar, pero no necesariamente el séptimo salario distinto más alto.


DENSE_RANK vs RANK vs ROW_NUMBER

Esta diferencia es muy importante y aparece frecuentemente en entrevistas técnicas.

Supongamos los siguientes salarios:

10000
9000
9000
8000
7000

Con ROW_NUMBER():

SALARY   ROW_NUMBER
------   ----------
10000        1
9000         2
9000         3
8000         4
7000         5

Con RANK():

SALARY   RANK
------   ----
10000      1
9000       2
9000       2
8000       4
7000       5

Con DENSE_RANK():

SALARY   DENSE_RANK
------   ----------
10000        1
9000         2
9000         2
8000         3
7000         4

Podemos resumirlo así:

FunciónDuplicadosSalta posiciones
ROW_NUMBER()Posiciones diferentesNo
RANK()Misma posición
DENSE_RANK()Misma posiciónNo

Para obtener el séptimo salario diferente más alto, normalmente utilizaríamos:

DENSE_RANK()

Método 4: utilizando una subconsulta correlacionada

También podemos resolver el problema sin utilizar funciones analíticas.

SELECT DISTINCT e1.salary
FROM employees e1
WHERE 6 = (
    SELECT COUNT(DISTINCT e2.salary)
    FROM employees e2
    WHERE e2.salary > e1.salary
);

Esta solución es particularmente interesante para entender la lógica detrás del problema.

La consulta busca un salario para el cual existan exactamente:

6 salarios diferentes mayores

Si existen seis salarios mayores, entonces el salario actual ocupa la posición:

7

Conceptualmente:

6 salarios mayores
        +
salario actual
        =
séptimo salario más alto

Obtener los empleados que reciben el séptimo salario más alto

En muchas situaciones no queremos únicamente conocer el salario.

También queremos saber qué empleados reciben ese salario.

Podemos utilizar:

SELECT employee_id,
       first_name,
       last_name,
       salary
FROM (
    SELECT employee_id,
           first_name,
           last_name,
           salary,
           DENSE_RANK() OVER (ORDER BY salary DESC) AS salary_rank
    FROM employees
)
WHERE salary_rank = 7;

Si varios empleados reciben el mismo séptimo salario, todos aparecerán en el resultado.


Obtener cualquier N salario más alto

Una de las ventajas de esta solución es que podemos adaptarla fácilmente.

Por ejemplo, para obtener el quinto salario más alto:

WHERE salary_rank = 5;

Para obtener el décimo salario más alto:

WHERE salary_rank = 10;

La consulta genérica sería:

SELECT *
FROM (
    SELECT employee_id,
           first_name,
           last_name,
           salary,
           DENSE_RANK() OVER (ORDER BY salary DESC) AS salary_rank
    FROM employees
)
WHERE salary_rank = N;

Donde:

N = posición que queremos encontrar

Los 7 salarios más altos

También podemos modificar la consulta para recuperar los primeros siete salarios:

SELECT employee_id,
       first_name,
       last_name,
       salary
FROM (
    SELECT employee_id,
           first_name,
           last_name,
           salary,
           DENSE_RANK() OVER (ORDER BY salary DESC) AS salary_rank
    FROM employees
)
WHERE salary_rank <= 7
ORDER BY salary DESC;

Esto devuelve todos los empleados cuyos salarios se encuentran entre los siete salarios diferentes más altos de la empresa.


La solución recomendada

Para una base de datos moderna, una solución clara y fácil de mantener sería:

SELECT employee_id,
       first_name,
       last_name,
       salary
FROM (
    SELECT employee_id,
           first_name,
           last_name,
           salary,
           DENSE_RANK() OVER (ORDER BY salary DESC) AS salary_rank
    FROM employees
)
WHERE salary_rank = 7;

Su principal ventaja es que expresa directamente lo que queremos hacer:

EMPLOYEES
    │
    ▼
ORDER BY SALARY DESC
    │
    ▼
DENSE_RANK()
    │
    ▼
RANK = 7
    │
    ▼
7º SALARIO MÁS ALTO

Una pregunta clásica de entrevista SQL

Cuando un entrevistador pregunta:

¿Cómo obtendrías el séptimo salario más alto de la tabla EMPLOYEES?

Antes de escribir la consulta conviene aclarar:

¿Quieres el séptimo empleado después de ordenar los salarios o el séptimo salario distinto más alto?

Esta pequeña diferencia determina qué función debemos utilizar.

Si necesitamos el séptimo registro:

ROW_NUMBER()

Si necesitamos el séptimo salario distinto:

DENSE_RANK()

Comprender esta diferencia demuestra no solamente que sabemos escribir SQL, sino que comprendemos cómo funcionan las funciones analíticas y el manejo de valores duplicados.

Conclusión

SQL ofrece varias formas de obtener el séptimo salario más alto de una tabla.

Podemos utilizar:

DENSE_RANK()
ROW_NUMBER()
RANK()
DISTINCT + OFFSET/FETCH
Subconsultas

Sin embargo, para encontrar el séptimo salario distinto más alto, una de las soluciones más claras es:

DENSE_RANK() OVER (ORDER BY salary DESC)

Las funciones analíticas son herramientas extremadamente poderosas para administradores de bases de datos, desarrolladores y analistas SQL.

Dominar ROW_NUMBER(), RANK() y DENSE_RANK() permite resolver de forma elegante problemas relacionados con Top-N queries, rankings, salarios, ventas, estadísticas y análisis de datos.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *