Ответ
Агрегатные функции (COUNT, SUM, AVG, MAX, MIN) почти всегда используются в комбинации с оператором GROUP BY, который группирует строки для вычислений. С этой связкой также часто применяются:
HAVING— для фильтрации результатов после агрегации (в отличие отWHERE, который фильтрует строки до).ORDER BY— для сортировки итоговых агрегированных данных.JOIN— для объединения данных из нескольких таблиц перед группировкой и агрегацией.
Пример SQL-запроса:
SELECT
department_id,
COUNT(*) AS employee_count,
AVG(salary) AS avg_salary
FROM employees
WHERE hire_date > '2020-01-01' -- Фильтрация ДО группировки
GROUP BY department_id -- Группировка по отделу
HAVING COUNT(*) > 3 -- Фильтрация ПОСЛЕ группировки
ORDER BY avg_salary DESC; -- Сортировка результата
Аналогия в Java Stream API:
Map<Department, Double> avgSalaryByDept = employees.stream()
.filter(e -> e.getHireDate().isAfter(LocalDate.of(2020, 1, 1)))
.collect(Collectors.groupingBy(
Employee::getDepartment, // Аналог GROUP BY
Collectors.averagingDouble(Employee::getSalary) // Аналог AVG()
));
// Дальнейшая фильтрация результата будет аналогом HAVING Ответ 18+ 🔞
Да ты посмотри, какая хуйня интересная! Эти ваши агрегатные функции — COUNT, SUM, AVG и прочие — они ж, блядь, как одиночки-то, нихуя не умеют. Ну посчитает он что-то по всей таблице разом, и что? Пиздец скучно.
А вся магия, сука, начинается, когда к ним приплетается GROUP BY. Вот это уже дело! Он берёт и раскидывает все строки по кучкам, как умный дворник. По отделам, по годам, по чёрту лысому — как скажешь. И вот тогда каждая функция начинает работать внутри своей кучи. Красота, ёпта!
Но и это ещё не всё, охуеть! Рядом с этой парочкой вечно крутятся ещё трое прихвостней:
HAVING— это, блядь, вышибала после вечеринки.WHEREотсеивает мудаков на входе в клуб, аHAVINGуже выпинывает те группы, которые внутри натворили делов (типа «у вас средняя зарплата меньше трёхсот, идите нахуй»).ORDER BY— ну это понятно, чтоб красиво было, отсортировать итоги.JOIN— а это чтобы перед тем, как группировать, натащить данных из других таблиц, собрать полную картину, блядь.
Смотри, как это в деле выглядит, прям как в жизни:
SELECT
department_id, -- Группируем по отделам, бля
COUNT(*) AS employee_count, -- Считаем, сколько лохов в каждом
AVG(salary) AS avg_salary -- И какая у них средняя тяга
FROM employees
WHERE hire_date > '2020-01-01' -- Берём только тех, кого наняли после 2020 (фильтр ДО группировки)
GROUP BY department_id -- Вот она, сука, группировка!
HAVING COUNT(*) > 3 -- Оставляем только отделы, где больше 3 человек (фильтр ПОСЛЕ!)
ORDER BY avg_salary DESC; -- Выводим от самых щедрых к самым жадным
А в Java, представляешь, та же хуйня, только в профиль! Там свои потоки (Stream), но логика — один в один, ебать мои старые костыли.
Map<Department, Double> avgSalaryByDept = employees.stream()
.filter(e -> e.getHireDate().isAfter(LocalDate.of(2020, 1, 1))) // Аналог WHERE
.collect(Collectors.groupingBy(
Employee::getDepartment, // Вот он, ёбаный GROUP BY!
Collectors.averagingDouble(Employee::getSalary) // А это наш AVG()
));
// А чтобы HAVING сделать — потом по этой мапе пройтись и отфильтровать, где значение не устраивает.
Вот и вся наука. Сгруппировал, посчитал, отфильтровал что надо. Главное — не перепутай WHERE с HAVING, а то получишь ерунду, в рот меня чих-пых!