Какие операторы SQL часто используются вместе с агрегатными функциями?

Ответ

Агрегатные функции (COUNT, SUM, AVG, MAX, MIN) почти всегда используются в комбинации с оператором GROUP BY, который группирует строки для вычислений. С этой связкой также часто применяются:

  1. HAVING — для фильтрации результатов после агрегации (в отличие от WHERE, который фильтрует строки до).
  2. ORDER BY — для сортировки итоговых агрегированных данных.
  3. 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. Вот это уже дело! Он берёт и раскидывает все строки по кучкам, как умный дворник. По отделам, по годам, по чёрту лысому — как скажешь. И вот тогда каждая функция начинает работать внутри своей кучи. Красота, ёпта!

Но и это ещё не всё, охуеть! Рядом с этой парочкой вечно крутятся ещё трое прихвостней:

  1. HAVING — это, блядь, вышибала после вечеринки. WHERE отсеивает мудаков на входе в клуб, а HAVING уже выпинывает те группы, которые внутри натворили делов (типа «у вас средняя зарплата меньше трёхсот, идите нахуй»).
  2. ORDER BY — ну это понятно, чтоб красиво было, отсортировать итоги.
  3. 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, а то получишь ерунду, в рот меня чих-пых!