Volver a la página principal
viernes 27 septiembre 2024
16

Cómo clasificar filas con DENSE_RANK en SQL Server

¿Qué es DENSE_RANK y para qué se usa?

DENSE_RANK es una función de ventana que devuelve el rango de cada fila dentro de una partición (grupo), ordenado según la columna o columnas especificadas en la cláusula ORDER BY. Si varias filas tienen el mismo valor en el criterio de orden, comparten el mismo rango, y la siguiente fila tendrá el rango siguiente inmediato (sin saltos).

Se usa en escenarios como:

  • Clasificación de elementos con posiciones consecutivas.
  • Ranking en competiciones o puntuaciones.
  • Realizar análisis comparativos entre categorías.
  • Calcular posiciones en un conjunto de datos agrupados sin dejar huecos en la numeración.

Sintaxis de DENSE_RANK

DENSE_RANK() OVER ( [PARTITION BY column1, column2, ...] ORDER BY column_name [ASC|DESC] )
  • PARTITION BY: (Opcional) Divide el conjunto de resultados en particiones o grupos, y reinicia la numeración para cada partición.
  • ORDER BY: Especifica cómo se deben ordenar las filas dentro de cada partición (o del conjunto completo).

Diferencia entre RANK, DENSE_RANK y ROW_NUMBER

  • RANK: Asigna el mismo rango a filas con valores idénticos, pero deja huecos en la numeración para la siguiente fila (por ejemplo, 1, 2, 2, 4).
  • DENSE_RANK: Asigna el mismo rango a valores iguales, pero no deja huecos en la secuencia de rangos (por ejemplo, 1, 2, 2, 3).
  • ROW_NUMBER: Asigna un número único a cada fila, sin considerar empates.

Ejemplos de uso de DENSE_RANK

Clasificar empleados por salario

Supongamos que tienes una tabla Empleados con las columnas EmpleadoID, Nombre y Salario, y quieres clasificar a los empleados según su salario en orden descendente:

SELECT EmpleadoID, Nombre, Salario,
       DENSE_RANK() OVER (ORDER BY Salario DESC) AS RangoSalario
FROM Empleados;

Resultado:

EmpleadoID | Nombre  | Salario | RangoSalario
-----------|---------|---------|-------------
1          | Ana     | 5000    | 1
3          | Juan    | 4500    | 2
4          | Luis    | 4500    | 2
5          | Pedro   | 3500    | 3

Las filas con el mismo salario (Juan y Luis) reciben el mismo rango (2), y el siguiente rango es 3 (sin saltar números).

Calcular el rango de ventas por departamento

Si deseas clasificar a los empleados dentro de cada departamento según sus ventas, utiliza la cláusula PARTITION BY para agrupar por Departamento:

SELECT Departamento, EmpleadoID, Nombre, Ventas,
       DENSE_RANK() OVER (PARTITION BY Departamento ORDER BY Ventas DESC) AS RangoVentas
FROM Empleados;

Resultado:

Departamento | EmpleadoID | Nombre | Ventas | RangoVentas
-------------|------------|--------|--------|------------
Ventas       | 1          | Ana    | 1500   | 1
Ventas       | 2          | Luis   | 1300   | 2
Ventas       | 3          | Juan   | 1300   | 2
Soporte      | 4          | Pedro  | 900    | 1
Soporte      | 5          | Marta  | 700    | 2

El ranking se reinicia para cada Departamento, calculando los rangos dentro de cada grupo de manera independiente.

Seleccionar los 3 mejores productos de cada categoría

Si tienes una tabla Productos con las columnas Categoria, NombreProducto y Ventas, y deseas encontrar los 3 productos más vendidos por categoría:

WITH RankingProductos AS (
    SELECT Categoria, NombreProducto, Ventas,
           DENSE_RANK() OVER (PARTITION BY Categoria ORDER BY Ventas DESC) AS RangoVentas
    FROM Productos
)
SELECT Categoria, NombreProducto, Ventas
FROM RankingProductos
WHERE RangoVentas <= 3;

Resultado:

Categoria   | NombreProducto | Ventas
------------|----------------|-------
Electrónica | TV             | 2000
Electrónica | Laptop         | 1500
Electrónica | Tablet         | 1200
Muebles     | Sofá           | 900
Muebles     | Mesa           | 800
Muebles     | Silla          | 700

La consulta devuelve solo los 3 productos con mayor volumen de ventas dentro de cada categoría.

Eliminar duplicados basados en el rango

Puedes usar DENSE_RANK para identificar y eliminar duplicados, manteniendo solo la primera aparición de cada conjunto de valores:

WITH Duplicados AS (
    SELECT *, 
           DENSE_RANK() OVER (PARTITION BY Nombre ORDER BY EmpleadoID) AS Rango
    FROM Empleados
)
DELETE FROM Duplicados WHERE Rango > 1;

Esto elimina todas las filas que tengan un rango mayor a 1, manteniendo solo la primera fila para cada nombre.

Mostrar los N productos más vendidos en general

Si quieres ver solo los 3 productos más vendidos en todo el conjunto de datos:

SELECT NombreProducto, Ventas, 
       DENSE_RANK() OVER (ORDER BY Ventas DESC) AS Rango
FROM Productos
WHERE DENSE_RANK() OVER (ORDER BY Ventas DESC) <= 3;

Este ejemplo devuelve los 3 productos más vendidos, independientemente de su categoría.

Consideraciones importantes

  • DENSE_RANK requiere una cláusula ORDER BY dentro de la cláusula OVER para definir cómo se calculan los rangos.
  • El rendimiento de DENSE_RANK puede verse afectado en tablas grandes con muchos grupos o particiones, especialmente si se usa en combinación con muchas columnas en ORDER BY.
  • DENSE_RANK no deja huecos en la numeración de rangos, lo cual lo diferencia de RANK, que sí lo hace en casos de empate.

Referencia oficial

Para más información sobre DENSE_RANK, consulta la documentación oficial de Microsoft.

Compartir:
Creado por:
Author photo

Jorge García

Fullstack developer