Собесов

SQL — разница среднего дохода у клиентов с чётными и нечётными ID

SQLCASE WHEN внутри агрегатовСредняяMiddle

Условие

В таблице task_1 есть ID (целое) и PROFIT_FAMILY (доход семьи). Посчитайте, насколько в среднем доход семьи у клиентов с ID = 2n (чётный) больше дохода у клиентов с ID = 2n+1 (нечётный), где n — произвольное целое.

То есть нужно: AVG(PROFIT_FAMILY | ID чётное) − AVG(PROFIT_FAMILY | ID нечётное). Округлить до 2 знаков.

Решение

Подход

Классический паттерн conditional aggregation: внутри одного SELECT с помощью CASE WHEN строим две «параллельные» подвыборки и считаем по ним агрегаты. Никаких подзапросов и JOIN не нужно.

Чётность определяется через остаток от деления: ID % 2 = 0 (Postgres/MySQL) или MOD(ID, 2) = 0.

Реализация

SELECT
  ROUND(
    AVG(CASE WHEN ID % 2 = 0  THEN profit_family END) -
    AVG(CASE WHEN ID % 2 != 0 THEN profit_family END),
    2
  ) AS fam_diff
FROM task_1;

CASE WHEN ... THEN x END (без ELSE) подставит NULL для «другой» половины — а AVG корректно игнорирует NULL и среднее берётся только по матчующим строкам.

Альтернатива: через FILTER

SELECT
  ROUND(
    AVG(profit_family) FILTER (WHERE ID % 2 = 0)
  - AVG(profit_family) FILTER (WHERE ID % 2 = 1),
    2
  ) AS fam_diff
FROM task_1;

Чище читается, но FILTER есть не во всех СУБД.

Альтернатива: через GROUP BY + LEAD/LAG или поворот

Можно сгруппировать по чётности и затем вычесть, но для разовой пары групп это избыточно.

Подводные камни

  1. Учёт ELSE. Если случайно поставить ELSE 0, AVG начнёт считать нули у «другой половины» как валидные значения и среднее уйдёт в пол. Без ELSENULL и они игнорируются.
  2. % в SQL Server. В MS SQL % работает, но возвращает тот же тип; в Oracle нужно MOD(ID, 2). На MySQL/Postgres % ок.
  3. Знак. Условие задачи — «чётные больше нечётных». Разница может оказаться отрицательной — это и будет ответ, не нужно брать модуль.
  4. NULL в ID. Если в ID есть NULL, ID % 2 даст NULL — такая запись не попадёт ни в одну ветку, что корректно.
  5. NULL в profit_family. AVG их игнорирует. Если задача требует «считать как 0» — нужно явно COALESCE(profit_family, 0).

Эталонный ответ

SELECT ROUND(
  AVG(CASE WHEN id % 2 = 0  THEN profit_family END) -
  AVG(CASE WHEN id % 2 != 0 THEN profit_family END),
2) AS fam_diff
FROM task_1;

Положительное значение → у «чётных» клиентов в среднем доход выше; отрицательное → ниже. Если значение близко к нулю на тестовых данных, это нормально: чётность ID — обычно случайность, и эффекта быть не должно.

Хочешь увидеть разбор?

Зарегистрируйся бесплатно — откроется развёрнутое решение этой задачи и ещё 4 на выбор.

Зарегистрироваться и увидеть разбор
Уже есть аккаунт? Войти