UpPetto

This is a real course generated by UpPetto — unedited.

AI-generated · source-grounded review: written by two AI models, cross-checked by a third. Yours takes ~5 minutes.

Create my own course

Основы оконных функций: ROW_NUMBER, RANK, DENSE_RANK

Pareto core

Оконные функции позволяют выполнять вычисления над набором строк, связанных с текущей строкой, при этом сохраняя детализацию исходных данных — в отличие от GROUP BY, который сворачивает строки в агрегаты. Функции ранжирования — ROW_NUMBER, RANK и DENSE_RANK — особенно полезны для нумерации записей внутри групп, поиска топ-N элементов и определения порядка событий.

Синтаксис оконных функций

Оконная функция применяется с использованием конструкции OVER(), которая определяет "окно" — набор строк для вычисления:

SELECT 
    column1,
    column2,
    WINDOW_FUNCTION() OVER (
        PARTITION BY column3 
        ORDER BY column4
    ) AS result
FROM table_name;

Ключевые компоненты:

  • PARTITION BY — разбивает данные на группы (аналог GROUP BY), но без потери детализации. Функция применяется независимо внутри каждой группы.
  • ORDER BY — определяет порядок строк внутри окна или партиции. Для функций ранжирования этот параметр обязателен.

ROW_NUMBER: последовательная нумерация

ROW_NUMBER() присваивает уникальный последовательный номер каждой строке внутри партиции. Даже если значения в столбце сортировки одинаковые, номера будут различаться.

Пример: Пронумеруем заказы каждого клиента по дате оформления:

SELECT 
    customer_id,
    order_id,
    order_date,
    amount,
    ROW_NUMBER() OVER (
        PARTITION BY customer_id 
        ORDER BY order_date
    ) AS order_number
FROM orders;
customer_id order_id order_date amount order_number
101 5001 2024-01-10 1500 1
101 5012 2024-01-15 2300 2
101 5023 2024-02-01 1800 3
102 5002 2024-01-12 900 1
102 5018 2024-01-20 1200 2

Нумерация начинается заново для каждого клиента. Это позволяет легко найти первый заказ каждого клиента, добавив WHERE order_number = 1 во внешний запрос.

RANK и DENSE_RANK: ранжирование с учетом равенства

Когда несколько строк имеют одинаковые значения в столбце сортировки, ROW_NUMBER все равно присвоит им разные номера. Функции RANK и DENSE_RANK работают иначе:

  • RANK() — присваивает одинаковый ранг строкам с равными значениями, но следующий ранг "пропускает" номера. Если две строки получили ранг 2, следующая строка получит ранг 4.
  • DENSE_RANK() — также присваивает одинаковый ранг равным значениям, но следующий ранг идет последовательно без пропусков (после двух строк с рангом 2 идет ранг 3).

Пример: Ранжируем продукты по выручке внутри каждой категории:

SELECT 
    category,
    product_name,
    revenue,
    RANK() OVER (PARTITION BY category ORDER BY revenue DESC) AS rank_with_gaps,
    DENSE_RANK() OVER (PARTITION BY category ORDER BY revenue DESC) AS dense_rank
FROM products;
category product_name revenue rank_with_gaps dense_rank
Electronics Laptop 50000 1 1
Electronics Tablet 50000 1 1
Electronics Phone 35000 3 2
Electronics Headphones 12000 4 3
Books Novel A 8000 1 1
Books Novel B 6000 2 2

Обратите внимание: Laptop и Tablet имеют одинаковую выручку, поэтому оба получили ранг 1. RANK() присвоил следующему продукту ранг 3 (пропустив 2), а DENSE_RANK() — ранг 2.

Практическое применение: топ-3 товара по продажам

Частая задача аналитика — найти топ-N элементов в каждой группе. С помощью DENSE_RANK это решается в два шага:

WITH ranked_products AS (
    SELECT 
        category,
        product_name,
        total_sales,
        DENSE_RANK() OVER (PARTITION BY category ORDER BY total_sales DESC) AS sales_rank
    FROM product_sales
)
SELECT 
    category,
    product_name,
    total_sales
FROM ranked_products
WHERE sales_rank <= 3
ORDER BY category, sales_rank;

Этот запрос вернет три самых продаваемых товара в каждой категории, даже если на третьем месте несколько товаров с одинаковыми продажами.

Ключевые выводы

  • ROW_NUMBER() — для уникальной нумерации строк, когда важна последовательность (первый заказ, последнее действие).
  • RANK() — для ранжирования с пропусками, когда нужно показать "настоящее" место в рейтинге.
  • DENSE_RANK() — для компактного ранжирования без пропусков, удобно для фильтрации топ-N.
  • PARTITION BY создает независимые группы для ранжирования, ORDER BY определяет критерий сортировки внутри окна.

AI-generated · source-grounded review

🛡 Fact-checked: 3 risky claims verified · 0 removed · confidence: high
[verified] Все примеры с конкретными датами (2024-01-10, 2024-01-15 и т.д.) и числовыми значениями
Это иллюстративные примеры для обучения, не утверждения о реальных данных
[verified] ROW_NUMBER, RANK, DENSE_RANK присваивают номера/ранги согласно описанной логике
Стандартное поведение оконных функций SQL
[verified] PARTITION BY разбивает данные на группы без потери детализации
Соответствует описанию оконных функций в базе знаний

A second opinion has not checked this lesson.

Key concepts: ROW_NUMBER RANK PARTITION BY ORDER BY в окнах
Tell me more 🔒 Didn't understand — explain simply 🔒 Show examples 🔒 Sources 🔒

On your own course these buttons answer instantly, quizzes track what you've mastered, and lessons adapt to your gaps. Sign up free →

Check yourself

1. Какая функция присвоит одинаковый ранг строкам с равными значениями, но следующий ранг будет идти без пропусков?
2. Для чего используется конструкция PARTITION BY в оконных функциях?
3. Чем ROW_NUMBER() отличается от RANK() при наличии строк с одинаковыми значениями в столбце сортировки?
Sign up free to check your answers