JavaRush /Курсы /SQL SELF /Использование PARTITION BY для разделения д...

Использование PARTITION BY для разделения данных на группы

SQL SELF
29 уровень , 3 лекция
Открыта

Представьте себе, что вы работаете официантом (или баристой, если вы любите кофе) в большом ресторане. Каждый день вы подводите итог по заработанным чаевым. Но есть нюанс: ресторан разделён на зоны, и вас интересует, сколько чаевых заработано в каждой зоне отдельно. PARTITION BY — это то, что SQL использует для "разделения ресторана на зоны".

Более формально, PARTITION BY используется в оконных функциях для разделения всех строк таблицы на отдельные группы (или "разделы"). Внутри каждой группы оконная функция выполняется заново. Это как если бы вы применяли функцию отдельно в каждом "разделе".

Пример: как это работает

Допустим, у нас есть таблица sales с данными о продажах:

region salesperson amount
North Alice 100
North Bob 200
South Alice 150
South Charlie 250

Если мы хотим вычислить, сколько денег заработал каждый продавец, но отдельно для каждого региона, PARTITION BY — это то, что нам нужно.

Синтаксис PARTITION BY

Синтаксис довольно прост:

оконная_функция() OVER (PARTITION BY столбец_или_столбцы)
  • оконная_функция() — это, например, SUM(), AVG(), ROW_NUMBER() и так далее.
  • PARTITION BY столбец — указывает, по какому столбцу нужно разделить строки.
  • OVER() — это оператор, который говорит SQL: "Выполни что-то в рамках указанного окна".

Пример: сумма по группам

Давайте вычислим сумму продаж для каждого региона:

SELECT
    region,
    salesperson,
    amount,
    SUM(amount) OVER (PARTITION BY region) AS total_sales_by_region
FROM sales;

Результат будет таким:

region salesperson amount total_sales_by_region
North Alice 100 300
North Bob 200 300
South Alice 150 400
South Charlie 250 400

Что происходит? SQL разбивает строки на группы по значению столбца region (North и South), затем применяет функцию SUM() отдельно для каждой группы. Как результат, строки внутри группы "North" получают одно и то же значение суммы, а строки внутри группы "South" — другое.

Примеры использования PARTITION BY

Давайте рассмотрим, как PARTITION BY может быть полезен в задачах реального мира.

Пример 1: Ранжирование внутри группы

Предположим, мы хотим ранжировать продавцов внутри каждого региона по количеству продаж. Для этого можно использовать комбинацию PARTITION BY и функции RANK():

SELECT
    region,
    salesperson,
    amount,
    RANK() OVER (PARTITION BY region ORDER BY amount DESC) AS rank_in_region
FROM sales;

Результат:

region salesperson amount rank_in_region
North Bob 200 1
North Alice 100 2
South Charlie 250 1
South Alice 150 2

Функция RANK() присваивает ранг внутри каждой группы region, начиная с 1. Заметьте, что для каждой группы ранги начинаются с единицы.

Пример 2: Сравнение каждого значения со средним в группе

Допустим, мы хотим посмотреть, сколько каждый продавец заработал относительно среднего по своему региону. Используем AVG():

SELECT
    region,
    salesperson,
    amount,
    AVG(amount) OVER (PARTITION BY region) AS avg_sales_by_region,
    amount - AVG(amount) OVER (PARTITION BY region) AS diff_from_avg
FROM sales;

Результат:

region salesperson amount avg_sales_by_region diff_from_avg
North Alice 100 150 -50
North Bob 200 150 50
South Alice 150 200 -50
South Charlie 250 200 50

Сначала SQL разделяет строки на группы по region. Затем вычисляет среднее значение AVG(amount) для каждой группы. Наконец, для каждой строки вычисляет разницу между её значением и средним.

Пример 3: Нумерация строк внутри группы

Скажем, вы хотите пронумеровать все транзакции внутри каждой группы региона. Используем ROW_NUMBER():

SELECT
    region,
    salesperson,
    amount,
    ROW_NUMBER() OVER (PARTITION BY region ORDER BY amount DESC) AS row_number
FROM sales;

Результат:

region salesperson amount row_number
North Bob 200 1
North Alice 100 2
South Charlie 250 1
South Alice 150 2

Сравнение с GROUP BY

Нередко возникает путаница между PARTITION BY и GROUP BY. Давайте сравним их:

GROUP BY

GROUP BY изменяет структуру выходного результата — он преобразует строки таблицы в агрегаты. Например:

SELECT
    region,
    SUM(amount) AS total_sales
FROM sales
GROUP BY region;

Результат:

region total_sales
North 300
South 400

Здесь мы теряем информацию о продавцах, так как данные агрегируются.

PARTITION BY

PARTITION BY, наоборот, не изменяет структуру. Мы всё ещё видим каждую строку, но у нас есть дополнительные значения, рассчитанные по группам. То есть, PARTITION BY позволяет агрегировать без потери деталей.

Частые ошибки при использовании PARTITION BY

Ошибка 1: Забыли PARTITION BY

Иногда вы хотите группировать данные, но забываете использовать PARTITION BY. Например:

SELECT
    region,
    salesperson,
    amount,
    SUM(amount) OVER () AS total_sales
FROM sales;

Результат:

region salesperson amount total_sales
North Alice 100 700
North Bob 200 700
South Alice 150 700
South Charlie 250 700

Здесь SUM(amount) рассчитана для всей таблицы, а не отдельно для каждого региона. Если хотите учитывать регионы, не забудьте указать PARTITION BY region.

Ошибка 2: Неправильный порядок в ORDER BY

Порядок строк в рамках окна важен для функций, таких как RANK() или ROW_NUMBER(). Будьте внимательны, когда используете ORDER BY внутри OVER().

2
Задача
SQL SELF, 29 уровень, 3 лекция
Недоступна
Сумма продаж по регионам
Сумма продаж по регионам
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ