В чем отличие функции RANK() от DENSE_RANK()?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
RANK() vs DENSE_RANK() в SQL
Это две оконные функции в SQL, которые ранжируют строки, но различаются в обработке равных значений. Разберёмся в деталях с примерами.
Основное различие
RANK() — присваивает ранг каждой строке, пропуская ранги при наличии связей (равных значений)
DENSE_RANK() — присваивает ранг, но НЕ пропускает ранги; следующий ранг идёт сразу после предыдущего
Пример с данными
Представим таблицу студентов с баллами:
student_id | name | score
-----------|---------|-------
1 | Alice | 95
2 | Bob | 90
3 | Charlie | 90
4 | Diana | 85
5 | Eve | 85
6 | Frank | 85
Запрос:
SELECT
student_id,
name,
score,
RANK() OVER (ORDER BY score DESC) as rank_col,
DENSE_RANK() OVER (ORDER BY score DESC) as dense_rank_col,
ROW_NUMBER() OVER (ORDER BY score DESC) as row_number_col
FROM students
ORDER BY score DESC, name;
Результат:
student_id | name | score | rank | dense_rank | row_number
-----------|---------|-------|------|------------|----------
1 | Alice | 95 | 1 | 1 | 1
2 | Bob | 90 | 2 | 2 | 2
3 | Charlie | 90 | 2 | 2 | 3
4 | Diana | 85 | 4 | 3 | 4
5 | Eve | 85 | 4 | 3 | 5
6 | Frank | 85 | 4 | 3 | 6
Детальное объяснение
RANK():
- Alice с баллом 95 получает ранг 1
- Bob и Charlie оба с баллом 90 получают ранг 2
- Следующий ранг становится 4 (пропускаются ранги 3, потому что два человека имеют ранг 2)
- Diana, Eve и Frank все с баллом 85 получают ранг 4
Отсюда видно: есть 2 человека на ранге 2, поэтому следующий ранг 4, а не 3.
DENSE_RANK():
- Alice получает ранг 1
- Bob и Charlie оба получают ранг 2 (связь)
- Diana, Eve и Frank получают ранг 3 (следующий ранг идёт без пропусков)
Ранги идут подряд: 1, 2, 3 без пропусков.
Практические различия
Когда использовать RANK():
- Нужны позиции в конкурсе (1-е, 2-е, 4-е место)
- Спортивные турниры, где место пропускается из-за связей
- Когда важна реальная позиция с учётом дублей
Когда использовать DENSE_RANK():
- Нужны последовательные номера для группировки
- Работа с уровнями, категориями без пропусков
- Анализ перцентилей и квартилей
- Когда нужна компактная нумерация
Дополнительный пример: TOP-N по группам
-- Получить top-3 студента каждого класса без пропусков ранга
WITH ranked_students AS (
SELECT
class,
student_name,
score,
DENSE_RANK() OVER (PARTITION BY class ORDER BY score DESC) as rank
FROM students
)
SELECT *
FROM ranked_students
WHERE rank <= 3;
Если использовать RANK() и в классе три студента со 100 баллами, то RANK() выдаст им все ранг 1, а следующий будет ранг 4, и мы можем потерять нужных нам студентов. DENSE_RANK() будет более предсказуем.
Также есть ROW_NUMBER()
ROW_NUMBER() — присваивает уникальный номер каждой строке, игнорируя значения
- В нашем примере: 1, 2, 3, 4, 5, 6 независимо от баллов
- Используется когда нужен просто порядковый номер
Вывод
Выбор между RANK() и DENSE_RANK() зависит от бизнес-логики:
- RANK() отражает реальную позицию с пропусками
- DENSE_RANK() дает плотную нумерацию без пропусков