Перейти к основному содержимому
Модуль 7 · Урок 2 из 426/57 в курсе~14 min
Уроки модуля (2/4)

Оконные функции: ранжирование и расчеты по группам

Оконная функция — это функция, которая работает с «группой строк». (окно), но — в отличие от GROUP BY — не уменьшает количество строки: значение, вычисленное в окне, прикрепляется к каждой строке окончательный результат.

Это правильный инструмент для ранжирования, прогрессивной нумерации и процентов. над общей суммой группы и многие другие операции, которые неудобны или невозможно с GROUP BY.

Синтаксис: function() OVER (…).

SQL
ROW_NUMBER() OVER (PARTITION BY colonna ORDER BY colonna2)

Компоненты:

  • PARTITION BY — определяет «группы» (например, GROUP BY, но строки оставайтесь отдельно);
  • ORDER BY внутри OVER(…) — определяет порядок внутри перегородка.

OVER () (пустые скобки) означает «вся таблица как одно окно». Полезно для вычислений типа «процент от общего количества».

Функции ранжирования

SQL
ROW_NUMBER() OVER (PARTITION BY p ORDER BY o)
RANK()       OVER (PARTITION BY p ORDER BY o)
DENSE_RANK() OVER (PARTITION BY p ORDER BY o)

Отличия (со значениями 100, 100, 90, 80):

ФункцияПозиции
ROW_NUMBER1, 2, 3, 4 (всегда уникальные)
RANK1, 1, 3, 4 (связи разделяют позицию, оставляют «пробелы»)
DENSE_RANK1, 1, 2, 3 (связи делят позицию, без пропусков)

Пример: рейтинг продукта по категории.

SQL
SELECT name,
       category_id,
       price,
       RANK() OVER (PARTITION BY category_id ORDER BY price DESC) AS rank
FROM   products
ORDER BY category_id, rank;

Для каждого category_id RANK перезапускается с 1 и упорядочивается по убыванию цена: вы получаете рейтинг продуктов внутри каждой категории, в одной выстрел.

Прогрессивная нумерация

SQL
-- Progressive order number for each customer:
SELECT id,
       customer_id,
       ordered_at,
       ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY ordered_at) AS row_num
FROM   orders
ORDER BY customer_id, row_num;

Первый заказ каждого клиента будет иметь row_num = 1, второй 2 и т. д.

Попробуйте это

Упражнение#sql.m7.l2.e1
Попыток: 0Загрузка…

Для каждого продукта отображается название, идентификатор категории, цена и рейтинг (ранжирование по убыванию цены ВНУТРИ категории; используйте РАНГ). Упорядочите по возрастанию категории_id и возрастанию ранга.

Загрузка редактора…
Показать подсказку

РАЗДЕЛЕНИЕ ПО категориям_id групп, ПОРЯДОК ПО цене DESC заказов внутри группы.

Решение доступно после 3 попыток

Обзор упражнения

Упражнение#sql.m7.l2.e2
Попыток: 0Загрузка…

Для каждого заказа отображаются идентификатор, customer_id, order_at и row_num (прогрессивный ROW_NUMBER для каждого клиента, упорядоченный по возрастанию order_at). Упорядочить по customer_id и row_num.

Загрузка редактора…
Показать подсказку

ROW_NUMBER всегда уникален в пределах раздела.

Решение доступно после 3 попыток