Давай уявимо: ти слідкуєш за доходами своєї компанії, продажами в інтернет-магазині або навіть просто аналізуєш свої витрати за рік. Тобі потрібно не тільки бачити доходи чи витрати за кожен місяць, а й розуміти, як вони накопичуються від місяця до місяця.
Звичайні агрегатні функції (GROUP BY) тут не допоможуть — вони згрупують дані і повернуть один рядок на групу. А що, якщо ми хочемо бачити кожен місяць і при цьому рахувати накопичувальну суму? Ось тут і виручає SUM() у зв'язці з віконними функціями.
Основи використання віконних функцій для накопичувальних сум
Віконні функції дозволяють виконувати агрегатні операції по віконних рамках. Завдяки цьому ми можемо, наприклад, складати значення в кожному рядку, але без видалення інших рядків. Більше ніяких жертв заради GROUP BY!
Синтаксис SUM() з віконною функцією
Ось базовий шаблон для використання накопичувальної суми:
SELECT
column_name,
SUM(column_name) OVER (PARTITION BY partition_column ORDER BY order_column) AS cumulative_sum
FROM
table_name;
Тут:
SUM(column_name)— підсумовує значення.OVER()— задає вікно для розрахунку.PARTITION BY— ділить дані на групи (опціонально).ORDER BY— задає порядок рядків всередині вікна.
Приклад: накопичувальний дохід по місяцях
Уявімо таблицю твоїх доходів:
| місяць | дохід |
|---|---|
| 2023-01 | 1000 |
| 2023-02 | 1500 |
| 2023-03 | 2000 |
Ми хочемо побачити дохід за кожен місяць і накопичувальний підсумок. Спробуємо написати SQL-запит:
SELECT
місяць,
дохід,
SUM(дохід) OVER (ORDER BY місяць) AS накопичувальний_дохід
FROM
доходи;
Результат:
| місяць | дохід | накопичувальний_дохід |
|---|---|---|
| 2023-01 | 1000 | 1000 |
| 2023-02 | 1500 | 2500 |
| 2023-03 | 2000 | 4500 |
Що відбувається:
ORDER BY місяцьвсерединіOVER()каже PostgreSQL, що рядки треба враховувати у хронологічному порядку.- Для кожного рядка сума рахується з урахуванням усіх попередніх рядків (і поточного).
Подумай уважно над тим, що тут відбувається. Для першого рядка SUM() рахує суму тільки 1-го рядка, для другого — суму двох рядків, для третього — суму трьох рядків. Саме тому важливий порядок сортування місяців!
Приклад: накопичувальний дохід по регіонах
Якщо у тебе була б таблиця продажів по регіонах, частинами вона могла б виглядати так:
| регіон | місяць | дохід |
|---|---|---|
| Північний | 2023-01 | 1000 |
| Північний | 2023-02 | 1500 |
| Південний | 2023-01 | 2000 |
| Південний | 2023-02 | 2500 |
Тепер ми хочемо рахувати накопичувальний дохід окремо для кожного регіону:
SELECT
регіон,
місяць,
дохід,
SUM(дохід) OVER (PARTITION BY регіон ORDER BY місяць) AS накопичувальний_дохід
FROM
продажі;
Результат буде таким:
| регіон | місяць | дохід | накопичувальний_дохід |
|---|---|---|---|
| Північний | 2023-01 | 1000 | 1000 |
| Північний | 2023-02 | 1500 | 2500 |
| Південний | 2023-01 | 2000 | 2000 |
| Південний | 2023-02 | 2500 | 4500 |
Тепер кожен регіон аналізується окремо (PARTITION BY регіон), але всередині регіону рядки впорядковуються по часу (ORDER BY місяць).
Ковзаюче середнє (AVG())
Окей, накопичувальні суми — це круто, але що, якщо ти хочеш аналізувати тренди, скажімо, за останні 3 місяці? Для цього підійде ковзаюче середнє.
Приклад: ковзаюче середнє доходів
Ми знову працюємо з таблицею доходи, і ось її дані:
| місяць | дохід |
|---|---|
| 2023-01 | 1000 |
| 2023-02 | 1500 |
| 2023-03 | 2000 |
| 2023-04 | 2500 |
Запит для розрахунку 3-місячного ковзаючого середнього:
SELECT
місяць,
дохід,
AVG(дохід) OVER (
ORDER BY місяць
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
) AS ковзаюче_середнє
FROM
доходи;
Результат:
| місяць | дохід | ковзаюче_середнє |
|---|---|---|
| 2023-01 | 1000 | 1000 |
| 2023-02 | 1500 | 1250 |
| 2023-03 | 2000 | 1500 |
| 2023-04 | 2500 | 2000 |
Пояснення:
ROWS BETWEEN 2 PRECEDING AND CURRENT ROWкаже PostgreSQL дивитись на поточний рядок і два попередні рядки для розрахунку середнього.- В результаті для кожного місяця ми бачимо середній дохід за останні 3 місяці.
Тобто для кожного рядка ми задаємо вікно у 3 рядки: поточний і два попередніх. А потім по ним рахуємо середнє. Дуже зручно.
Робота ORDER BY і його вплив
Віконні функції залежать від правильного порядку рядків. Якщо порядок вказаний неправильно (або взагалі не вказаний), результати можуть бути неочікуваними.
Приклад: помилки через відсутність ORDER BY
Якщо ми приберемо ORDER BY з OVER(), то замість накопичувальної суми отримаємо суму всіх доходів для кожного рядка:
SELECT
місяць,
дохід,
SUM(дохід) OVER () AS неправильна_накопичувальна_сума
FROM
доходи;
Результат:
| місяць | дохід | неправильнанакопичувальнасума |
|---|---|---|
| 2023-01 | 1000 | 7000 |
| 2023-02 | 1500 | 7000 |
| 2023-03 | 2000 | 7000 |
| 2023-04 | 2500 | 7000 |
Рядки не впорядковані, і замість накопичувальної суми функція просто застосовує підсумовування для всіх рядків без розбору.
Реальні кейси використання
Аналіз доходів:
- Накопичувальні суми дозволяють відслідковувати, як ростуть продажі чи доходи компанії.
- Ковзаюче середнє допомагає побачити "чистий" тренд без шумів.
Фінансове моделювання:
Банки та фінансові компанії використовують віконні функції для аналізу виплат, зростання заборгованостей та інших метрик.
Побудова часових рядів:
Часові дані, такі як кількість користувачів онлайн, перегляди сторінок, виручка і т.п., ідеально аналізуються з SUM() та AVG().
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ