DÍA 32Fechas y funciones de ventana · SQL para Análisis de Datos

Elige cómo representar empates al asignar posiciones a periodos.

Día 32 18 minIntermedio

Comparar ROW_NUMBER, RANK y DENSE_RANK

Objetivos

Al terminar podrás elegir una función de ranking según la forma en que quieres tratar empates.

Concepto

ROW_NUMBER() da a cada fila un número distinto. RANK() comparte puesto entre empates y deja un hueco después. DENSE_RANK() comparte puesto, pero no deja huecos.

Las tres son funciones de ventana: el CTE agrupa primero los pagos por mes y luego la ventana asigna una posición a cada fila mensual. El ORDER BY final decide la presentación; para ROW_NUMBER incluye un desempate estable.

Ejemplo

WITH monthly AS (
  SELECT
    DATE_FORMAT(payment_date, '%Y-%m') AS payment_month,
    SUM(amount) AS total_amount
  FROM payment
  GROUP BY DATE_FORMAT(payment_date, '%Y-%m')
)
SELECT
  payment_month,
  ROUND(total_amount, 2) AS total_amount,
  ROW_NUMBER() OVER (ORDER BY total_amount DESC, payment_month) AS row_number_rank,
  RANK() OVER (ORDER BY total_amount DESC) AS rank_with_gaps,
  DENSE_RANK() OVER (ORDER BY total_amount DESC) AS dense_rank_value
FROM monthly
ORDER BY total_amount DESC, payment_month;

Un empate depende de los valores de los datos. ROW_NUMBER usa el mes como desempate, mientras RANK y DENSE_RANK comparan solo el total.

Práctica guiada

  1. Cambia el orden a ASC y observa qué periodo queda primero.
  2. Quita payment_month de ROW_NUMBER y explica por qué el orden entre empates puede variar.
  3. Busca dos filas con el mismo total en un conjunto de prueba para observar el hueco de RANK.

Reto

Asigna una posición única a las tiendas por importe total. Usa una clave estable para resolver empates y explica cuándo preferirías RANK.

Ver respuesta al reto
WITH store_totals AS (
  SELECT s.store_id AS staff_primary_store_id,
         SUM(p.amount) AS total_amount
  FROM sakila.payment AS p
  JOIN sakila.staff AS s ON s.staff_id = p.staff_id
  GROUP BY s.store_id
)
SELECT staff_primary_store_id, ROUND(total_amount, 2) AS total_amount,
       ROW_NUMBER() OVER (ORDER BY total_amount DESC, staff_primary_store_id) AS position,
       RANK() OVER (ORDER BY total_amount DESC) AS rank_with_gaps
FROM store_totals
ORDER BY position;

El identificador de tienda desempata ROW_NUMBER; RANK es útil cuando se quiere compartir posición y dejar huecos tras empates.

Quiz

1. Después de dos filas empatadas en el primer lugar, ¿qué rango sigue con DENSE_RANK?
2. ¿Qué aporta PARTITION BY a una función de ventana?
3. ¿Qué define ORDER BY dentro de OVER?

Comprobación

Ya eliges cómo numerar empates. La siguiente lección compara un periodo con el anterior y el siguiente.

TU PROGRESO

Cargando estado…