🔥 Live Coding: зарплаты и средний доход по отделам

Задача: Есть таблица employee_salary:

• employee_id • salary_rur • bonus_rur • department_id

Нужно для каждого отдела посчитать:

• общее количество сотрудников • количество сотрудников с заполненной зарплатой • средний доход сотрудника

Где: доход = salary + bonus

⚠️ Важно: • если salary_rur is null → считаем как 0 • если bonus_rur is null → считаем как 0 • средний доход считаем только по тем сотрудникам, у которых есть хотя бы одно значение: salary_rur is not null или bonus_rur is not null

На выходе хотим получить:

• department_id • employees_cnt • employees_with_salary_cnt • avg_income

Решение:

select department_id, count() as employees_cnt, countIf(salary_rur is not null) as employees_with_salary_cnt, avg( case when salary_rur is not null or bonus_rur is not null then ifNull(salary_rur, 0) + ifNull(bonus_rur, 0) else null end ) as avg_income from employee_salary group by department_id order by department_id

🧠 Как здесь думаем:

Сначала считаем общее количество сотрудников в отделе. Это обычный count().

Дальше считаем количество сотрудников с заполненной зарплатой. Здесь важна именно заполненная salary_rur, поэтому используем:

countIf(salary_rur is not null)

Теперь самое важное — avg_income.

По условию: • null в salary считаем как 0 • null в bonus считаем как 0 • но если у сотрудника оба поля null, такого сотрудника в средний доход включать нельзя

Поэтому логика такая:

если есть хотя бы одно значение, считаем доход как:

ifNull(salary_rur, 0) + ifNull(bonus_rur, 0)

если оба поля null, возвращаем null

Почему это важно? Потому что avg() не учитывает null, а значит такие сотрудники автоматически не попадут в расчет среднего ✅

⚠️ Где можно ошибиться:

Просто написать:

avg(ifNull(salary_rur, 0) + ifNull(bonus_rur, 0))

Тогда сотрудники, у которых оба поля null, попадут в средний как 0. Это исказит результат ❌

Посчитать employees_with_salary_cnt через count()

Тогда туда попадут вообще все сотрудники, а нам нужны только те, у кого salary_rur заполнена.

Забыть, что bonus_rur тоже может быть null

Тогда сумма salary + bonus может стать null, и доход посчитается неправильно.

💡 Можно записать и чуть подробнее через CTE:

with prepared as ( select department_id, employee_id, salary_rur, bonus_rur, case when salary_rur is not null or bonus_rur is not null then ifNull(salary_rur, 0) + ifNull(bonus_rur, 0) else null end as income from employee_salary )

select department_id, count() as employees_cnt, countIf(salary_rur is not null) as employees_with_salary_cnt, avg(income) as avg_income from prepared group by department_id order by department_id

Этот вариант иногда удобнее, потому что бизнес-логику income видно отдельно.

🎯 Вывод:

Это хорошая задача на: • работу с NULL • условную агрегацию • аккуратный расчет среднего

Главная мысль: не каждый null нужно превращать в 0 бездумно. Иногда null нужно исключить из расчета, а иногда — заменить на 0 внутри формулы.

Именно на этом чаще всего и ломаются метрики 👌

🔥 Live Coding: зарплаты и средний доход по отделам
Задача:
Есть таблица employee\salary:
• employee\id
• salary\rur
• bonus\rur
• department\id
Нужно для каждого отдела посчитать:
• общее количество с... | Сетка — социальная сеть от hh.ru