Згадуємо, що агрегатні функції — це ті, які працюють одразу з кількома рядками даних і повертають один результат. У PostgreSQL ти часто будеш використовувати такі агрегатні функції:
SUM()— підсумовування даних.AVG()— знаходження середнього значення.MIN()— пошук мінімального значення.MAX()— пошук максимального значення.COUNT()— підрахунок рядків.
На перший погляд, все просто: передаєш у функцію стовпець або вираз — і отримуєш результат. Але що відбувається, якщо у стовпці трапляється NULL?
Поведінка NULL в агрегатах: короткий огляд
Ось тут починається найцікавіше:
SUM()іAVG()ігноруютьNULL. Якщо хоча б один запис має значенняNULL, він просто не враховується у розрахунках. В принципі, логічно: як зросте сума, якщо хтось "не прийшов на вечірку"? Або як рахувати середнє, якщо одного значення не вистачає?MIN()іMAX()також пропускаютьNULL. Вони знаходять мінімальне чи максимальне значення лише серед тих даних, які не єNULL. Тобто, якщо ти шукаєш наймолодшого співробітника, який не заповнив дату народження,NULLне стане переможцем.COUNT(*)враховує усі рядки, навіть ті, де єNULL. А отCOUNT(column)рахує лише ті рядки, де у вказаному стовпці є значення, тобтоNULLігнорується.
Давай розберемо це на прикладах.
Приклади використання агрегатних функцій з NULL
Ось таблиця students_scores, яка містить оцінки студентів за тест:
| student_id | name | score |
|---|---|---|
| 1 | Аліса | 85 |
| 2 | Боб | NULL |
| 3 | Чарлі | 92 |
| 4 | Дана | NULL |
| 5 | Єлена | 74 |
Тепер напишемо кілька запитів і розберемо їх результати:
- Сума всіх оцінок:
SUM()
SELECT SUM(score) AS total_score
FROM students_scores;
Результат:
| total_score |
|---|
| 251 |
Як бачиш, пропущені NULL значення просто не брали участі у підсумовуванні. Для Аліси (85), Чарлі (92) та Єлени (74) сума склала 251. Боб і Дана залишилися осторонь.
- Середня оцінка:
AVG()
SELECT AVG(score) AS average_score
FROM students_scores;
Результат:
| average_score |
|---|
| 83.67 |
Знову ж таки, NULL були проігноровані, і середнє рахувалося лише для тих, у кого є оцінки: (85 + 92 + 74) / 3 = 83.67.
- Мінімальна та максимальна оцінка:
MIN()іMAX()
SELECT
MIN(score) AS min_score,
MAX(score) AS max_score
FROM students_scores;
Результат:
| min_score | max_score |
|---|---|
| 74 | 92 |
Тут теж все просто: NULL значення знову проігноровані, і мінімальною стала оцінка 74, а максимальною — 92.
- Підрахунок рядків:
COUNT(*)vsCOUNT(column)
SELECT
COUNT(*) AS total_rows,
COUNT(score) AS non_null_scores
FROM students_scores;
Результат:
| total_rows | non_null_scores |
|---|---|
| 5 | 3 |
COUNT(*)врахував усі рядки, включаючи ті, деscoreдорівнюєNULL.COUNT(score)порахував лише ті рядки, у яких у стовпціscoreє значення.
Практичні кейси
Наводимо кілька практичних прикладів.
Приклад 1: Підрахунок співробітників з вказаною та невказаною зарплатою
Припустимо, у нас є таблиця employees із зарплатами.
| id | name | salary |
|---|---|---|
| 1 | Alex Lin | 50000 |
| 2 | Maria Chi | NULL |
| 3 | Anna Song | 60000 |
| 4 | Otto Art | NULL |
| 5 | Liam Park | 55000 |
Ми хочемо дізнатися, скільки співробітників вказали свою зарплату, а скільки — ні.
SELECT
COUNT(*) AS total_employees,
COUNT(salary) AS employees_with_salary,
COUNT(*) - COUNT(salary) AS employees_without_salary
FROM employees;
Тут:
COUNT(*)поверне загальну кількість співробітників.COUNT(salary)порахує, скільки співробітників вказали зарплату.- Щоб дізнатися кількість співробітників без зарплати, просто віднімаємо одне значення від іншого.
Результат
| total_employees | employees_with_salary | employees_without_salary |
|---|---|---|
| 5 | 3 | 2 |
Приклад 2: Розрахунок середньої ціни товарів з урахуванням відсутніх даних
Ти власник чарівної крамниці, і в таблиці products є колонка price, але у деяких товарів ціна ще не вказана.
| id | name | price |
|---|---|---|
| 1 | Magic Wand | 150 |
| 2 | Enchanted Cloak | NULL |
| 3 | Potion Bottle | 75 |
| 4 | Spell Book | 200 |
| 5 | Crystal Ball | NULL |
Тобі потрібно дізнатися середню ціну лише для тих товарів, де вона задана.
SELECT AVG(price) AS average_price
FROM products;
Результат:
| average_price |
|---|
| 141.6667 |
Якщо хочеш вказати ціну за замовчуванням для товарів без ціни (наприклад, зробити її 0), можна використати функцію COALESCE() з наступної лекції.
Приклад 3: Знаходження мінімального та максимального віку студентів
У таблиці students зберігається вік учнів, але для деяких він невідомий (NULL).
| id | name | age |
|---|---|---|
| 1 | Alex Lin | 20 |
| 2 | Maria Chi | NULL |
| 3 | Anna Song | 19 |
| 4 | Otto Art | 22 |
| 5 | Liam Park | NULL |
Ми хочемо дізнатися, хто наймолодший і найстарший студент.
SELECT
MIN(age) AS youngest_student,
MAX(age) AS eldest_student
FROM students;
Результат:
| youngest_student | eldest_student |
|---|---|
| 19 | 22 |
Цей запит поверне мінімальний і максимальний вік лише для тих студентів, чий вік вказаний. NULL знову буде пропущено.
Особливості та підводні камені
Коли працюєш з NULL в агрегатах, важливо пам’ятати про такі моменти:
- У сумі
SUM()і середньомуAVG()NULLне враховуються. Це можна використати, щоб не додавати "порожні" значення у розрахунки. - Якщо потрібно враховувати рядки з
NULLу стовпці, використовуйCOUNT(*). - При використанні
MIN()чиMAX(),NULLне впливає на результат. Але якщо весь стовпець заповнений лишеNULL, результатом буде тежNULL.
Поради для роботи з NULL
- Враховуй специфіку задачі. Важливо розуміти, чи потрібно враховувати
NULLу твоєму запиті. Іноді, як у випадку зAVG(), їх ігнорування — це саме те, що треба. А іноді, як при підрахунку загальної кількості, важливо врахувати і рядки зNULL. - Використовуй
COALESCE()за потреби. Якщо треба замінитиNULLзначенням за замовчуванням у розрахунках, функціяCOALESCE()стане твоїм другом (але це вже тема наступної лекції). - Не плутай
COUNT(*)іCOUNT(column). Це класична помилка новачків. Перший рахує рядки, другий — лише рядки з ненульовими значеннями.
Тепер ти знаєш, як хитрий мовчун NULL може впливати на агрегати. Це знання дозволить уникати неприємних сюрпризів і використовувати NULL у своїх інтересах. У наступній лекції ми розглянемо потужний інструмент COALESCE(), щоб справлятися з NULL ще ефективніше.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ