← Назад к вопросам

В чем отличие функции RANK() от DENSE_RANK()?

1.3 Junior🔥 121 комментариев
#SQL и базы данных

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

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() дает плотную нумерацию без пропусков