Ось про що ми ще не говорили, так це як відфільтрувати групи після застосування агрегатів? Іноді нам не потрібні всі факультети — тільки ті, де студентів більше сотні. Або нам важливо подивитись лише на відділи, де середня зарплата більша за 50,000. Сьогодні знайомимось з фільтрацією агрегованих даних через HAVING.
Навіщо нам HAVING, якщо є WHERE? Можна ж просто поставити WHERE після GROUP BY :)
Все не так просто! По-перше, порядок операторів у SQL фіксований і WHERE по цьому порядку виконується до GROUP BY.
А може можна посунути його після GROUP BY?
Теж ні! Дуже часто треба відфільтрувати рядки таблиці до групування. Потім виконати над відфільтрованими даними групування. А потім відкинути якісь непотрібні дані вже після групування.
Тоді може просто взяти оператор WHERE, скопіювати його, назвати HAVING і розмістити після GROUP BY?
Так, саме так і зробимо! :)
Відмінність HAVING від WHERE
WHERE фільтрує рядки до групування.
Уяви, що ти відбираєш торти за смаком: полуничні та шоколадні — залишаєш, а інші — в сторону. Це задача для WHERE.
HAVING фільтрує після того, як дані були згруповані і агрегатні функції зробили свою магію.
Наприклад, ти вже згрупував торти по столах, порахував їх кількість і тепер хочеш залишити лише ті столи, де тортів більше трьох.
Таким чином, HAVING використовується для фільтрації даних на рівні груп.
Синтаксис HAVING
Синтаксис майже такий самий, як у WHERE, але працює він трохи інакше:
SELECT стовпці, агрегатні_функції
FROM таблиця
GROUP BY стовпці
HAVING умова;
Етапи виконання:
- Спочатку рядки фільтруються через
WHERE. - Потім дані групуються за допомогою
GROUP BY. - До результатів групування застосовуються агрегатні функції.
- Нарешті, отриманий результат фільтрується через
HAVING.
Приклади використання HAVING
Приклад 1: Фільтрація факультетів з великою кількістю студентів
Ти хочеш дізнатись, які факультети в університеті мають більше 100 студентів. Припустимо, у нас є таблиця students:
| id | name | faculty |
|---|---|---|
| 1 | Alice | Engineering |
| 2 | Bob | Engineering |
| 3 | Charlie | Arts |
| 4 | Daisy | Business |
| 5 | ... | ... |
Запит:
SELECT faculty, COUNT(*) AS student_count
FROM students
GROUP BY faculty
HAVING COUNT(*) > 100;
Що тут відбувається:
- Спочатку ми групуємо студентів по стовпцю
facultyза допомогоюGROUP BY. - Потім агрегатна функція
COUNT(*)рахує кількість студентів на кожному факультеті. - Нарешті,
HAVINGвідкидає всі факультети, де студентів 100 або менше.
Результат:
| faculty | student_count |
|---|---|
| Engineering | 150 |
| Arts | 120 |
Приклад 2: Відділи з високою середньою зарплатою
Ти хочеш знайти лише ті відділи, де середня зарплата співробітників перевищує 50,000. Припустимо, у нас є таблиця employees:
| id | name | department | salary |
|---|---|---|---|
| 1 | Alice | IT | 60000 |
| 2 | Bob | HR | 45000 |
| 3 | Charlie | IT | 70000 |
| 4 | Daisy | HR | 52000 |
| 5 | ... | ... | ... |
Запит:
SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department
HAVING AVG(salary) > 50000;
Результат:
| department | avg_salary |
|---|---|
| IT | 65000 |
Зверни увагу: HAVING працює з результатами, які були пораховані після GROUP BY.
Порядок виконання WHERE, GROUP BY і HAVING
Фільтрація через WHERE і HAVING відбувається на різних етапах. Щоб краще зрозуміти різницю, давай глянемо на покроковий процес запиту:
WHERE: фільтрація рядків.На цьому етапі обробляються всі рядки таблиці. Якщо рядок не проходить умову
WHERE, вона взагалі не потрапляє в подальшу обробку.GROUP BY: групування рядків.Після фільтрації рядки об'єднуються в групи на основі стовпців, вказаних у
GROUP BY.Агрегатні функції:
До згрупованих даних застосовуються агрегатні функції, такі як
COUNT(),AVG(),SUM()і т.д.HAVING: фільтрація груп.На цьому етапі обробляються лише результати агрегатів. Умови
HAVINGзастосовуються тільки до груп.
Особливості роботи HAVING
Особливість 1: Робота з агрегатами
Головна відмінність HAVING від WHERE — це робота з агрегатними функціями. Наприклад:
SELECT department, AVG(salary)
FROM employees
GROUP BY department
HAVING AVG(salary) > 50000;
У цьому запиті AVG(salary) не можна використовувати всередині WHERE, бо WHERE обробляє рядки до виконання групування. Запит типу:
SELECT department, AVG(salary)
FROM employees
WHERE AVG(salary) > 50000
GROUP BY department;
викличе помилку: aggregate functions are not allowed in WHERE.
Особливість 2: Фільтрація без групування
Ти можеш використовувати HAVING навіть без явного GROUP BY. У такому випадку запит буде трактуватись як такий, що має одну групу — всі записи:
SELECT AVG(salary) AS avg_salary
FROM employees
HAVING AVG(salary) > 50000;
Практичний приклад
Припустимо, у нас є магазин і таблиця продажів sales:
| id | product_id | sales_amount |
|---|---|---|
| 1 | 101 | 200.00 |
| 2 | 102 | 300.00 |
| 3 | 101 | 400.00 |
| 4 | 103 | 150.00 |
Запит: знайти товари з загальним обсягом продажів більше 500.
SELECT product_id, SUM(sales_amount) AS total_sales
FROM sales
GROUP BY product_id
HAVING SUM(sales_amount) > 500;
Результат:
| product_id | total_sales |
|---|---|
| 101 | 600.00 |
Типові помилки
Використання агрегатів у WHERE:
Наприклад:
SELECT department, AVG(salary)
FROM employees
WHERE AVG(salary) > 50000
GROUP BY department;
Помилка: агрегатні функції не можна використовувати у WHERE.
Помилки з NULL:
Якщо дані містять NULL, фільтрація може давати неочікувані результати. Наприклад:
SELECT department, SUM(salary)
FROM employees
GROUP BY department
HAVING SUM(salary) > 0;
Якщо стовпець salary містить лише NULL, результат може бути нульовим або порожнім.
Вітаю. На цьому етапі ти вже можеш впевнено фільтрувати агреговані дані! Не забувай, що HAVING — це твій ключ до аналітики на рівні груп, де звичайного WHERE вже недостатньо.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ