JavaRush /Курси /SQL SELF /Типові помилки при роботі з агрегатами

Типові помилки при роботі з агрегатами

SQL SELF
Рівень 8 , Лекція 4
Відкрита

Тепер настав час зануритись у типові помилки, які виникають при використанні цих функцій. Навіть найдосвідченіші SQL-гуру іноді наступають на граблі, і наше завдання — навчитися ці граблі бачити й успішно їх обходити.

Ти колись писав запит, а він сварився на щось загадкове типу "column must appear in the GROUP BY clause or be used in an aggregate function"? Або, може, результат твого запиту виглядав дивно, а ти взагалі не розумів, чому? Це лише верхівка айсберга типових помилок при роботі з агрегатними функціями. Ця лекція — твій гайд по виживанню в морі помилок і непорозумінь.

Помилка 1: Використання неагрегованого стовпця поза GROUP BY

Проблема

Ти написав запит, який повертає агреговані дані, але по дорозі додав колонку, яка не є частиною групування і не обгорнута в агрегатну функцію. Наприклад:

SELECT department, salary, SUM(salary)
FROM employees
GROUP BY department;

PostgreSQL одразу скаже тобі:

ERROR: column "employees.salary" must appear in the GROUP BY clause or be used in an aggregate function

Чому так відбувається?

Коли ти використовуєш GROUP BY, PostgreSQL об'єднує рядки по вказаних стовпцях. Але якщо ти додаєш ще один стовпець (у цьому випадку salary), PostgreSQL не знає, що з ним робити. Він же не розуміє, ти хочеш одну зарплату, середнє значення чи щось інше.

Як виправити? Є два шляхи:

  1. Переконайся, що всі неагреговані колонки присутні у GROUP BY:
SELECT department, salary
FROM employees
GROUP BY department, salary;
  1. Або обгорни стовпець в агрегатну функцію, якщо це має сенс:
SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department;

Порада: якщо PostgreSQL свариться на GROUP BY, спитай себе: "А цей стовпець точно потрібен у запиті? Якщо так, то яку саме роль він грає?"

Помилка 2: Неправильна робота з COUNT() і NULL

Проблема: ти хочеш порахувати, скільки співробітників вказали свої бонуси, і пишеш:

SELECT COUNT(bonus) AS bonus_count
FROM employees;

Але раптом помічаєш, що результат менший, ніж очікував. Чому? Бо COUNT(column) ігнорує рядки, де column дорівнює NULL.

Рішення: якщо ти хочеш порахувати взагалі всі рядки, використовуй COUNT(*):

SELECT COUNT(*) AS total_count
FROM employees;

Або уточни, що тобі потрібні лише ті рядки, де бонус не NULL:

SELECT COUNT(bonus) AS bonus_count
FROM employees
WHERE bonus IS NOT NULL;

Підказка: якщо ти хочеш враховувати різницю між записами, що містять NULL, і повною відсутністю записів у таблиці, уважно обирай між COUNT(*) і COUNT(column).

Помилка 3: Забута фільтрація за допомогою HAVING замість WHERE

Проблема: ти хочеш знайти відділи, де середня зарплата перевищує 5000. Новачок може написати щось типу цього:

SELECT department, AVG(salary) AS avg_salary
FROM employees
WHERE AVG(salary) > 5000
GROUP BY department;

PostgreSQL видасть помилку:

ERROR: aggregate functions are not allowed in WHERE clause

Це відбувається, бо фільтрація на рівні WHERE відбувається до виконання групування, а агрегатні функції застосовуються вже після групування. Тобто, середня зарплата AVG(salary) ще не порахована на етапі виконання WHERE.

Щоб це виправити, використовуй HAVING для фільтрації агрегованих даних:

SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department
HAVING AVG(salary) > 5000;

Помилка 4: Фільтрація з WHERE і дезорієнтація в порядку виконання

Проблема: ти хочеш дізнатись кількість співробітників у відділах, де вік співробітників більше 30 років. Запит може виглядати так:

SELECT department, COUNT(*)
FROM employees
GROUP BY department
WHERE age > 30;

PostgreSQL знову тебе засмутить:

ERROR: syntax error at or near "WHERE"

Чому так відбувається? Оператор WHERE завжди обробляється раніше, ніж GROUP BY. У цьому випадку ти просто поставив WHERE не туди.

Щоб уникнути такого сценарію, поміняй порядок підрахунку: спочатку відфільтруй рядки, потім виконай групування.

SELECT department, COUNT(*)
FROM employees
WHERE age > 30
GROUP BY department;

Помилка 5: Використання NULL з SUM(), AVG() та іншими функціями

Проблема: ти хочеш знайти загальний бонус, виданий співробітникам, і пишеш:

SELECT SUM(bonus) AS total_bonus
FROM employees;

Але твій результат здається підозріло низьким. А все тому, що у половини співробітників бонуси не вказані, і ці NULL просто ігноруються.

Рішення: обробляй NULL заздалегідь. Наприклад, ти можеш замінити NULL на 0:

SELECT SUM(COALESCE(bonus, 0)) AS total_bonus
FROM employees;

Тепер всі NULL будуть замінені на 0, і сума стане коректною.

Ми детально розглянемо роботу функції COALESCE буквально через пару лекцій.

Помилка 6: використання кількох агрегатних функцій без розуміння їх зв'язку

Проблема: ти хочеш порахувати загальну кількість співробітників і загальну зарплату. Але пишеш щось, що повертає дивні результати:

SELECT COUNT(salary) AS count_salary, SUM(salary) AS total_salary
FROM employees;

Чому тут все може піти не так? Якщо у когось зарплата дорівнює NULL, COUNT(salary) і SUM(salary) дадуть різні результати, що може заплутати.

Завжди враховуй, що агрегатні функції працюють незалежно одна від одної. Якщо є NULL, то це призведе до різних результатів. Використовуй COALESCE або COUNT(*), щоб гарантувати однаковість:

SELECT COUNT(*) AS total_employees, SUM(COALESCE(salary, 0)) AS total_salary
FROM employees;

Помилка 7: Неоптимізовані запити з великими групуваннями

Проблема: ти запускаєш запит з великою кількістю групувань, і він працює годин п'ять замість п'яти хвилин:

SELECT department, job_title, location, COUNT(*)
FROM employees
GROUP BY department, job_title, location;

Перед виконанням групування подумай, чи дійсно всі стовпці потрібні у GROUP BY. Чим більше унікальних значень у групі, тим довше виконується запит. Якщо можливо, скороти групування:

SELECT department, COUNT(*)
FROM employees
GROUP BY department;

Ці помилки поширені, і навіть найдосвідченіші SQL-розробники стикаються з ними. Сподіваюсь, тепер тобі буде легше обходити ці підводні камені й писати запити, які працюють швидко, правильно і красиво.

1
Опитування
Групування даних, рівень 8, лекція 4
Недоступний
Групування даних
Групування даних
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ