🔥 Live Coding: сотрудники, которые работали в марте 2025 и получили salary_change > 200000
Задача: Есть 2 таблицы.
employees • employee_id • hire_date • fire_date • department_id
employee_events • employee_id • event_time • event_type • salary
Нужно найти сотрудников, которые:
• работали в марте 2025 • у которых последнее кадровое событие — salary_change • и зарплата после него больше 200000
На выходе хотим получить:
• employee_id • salary • event_time
Решение:
with active_in_march as ( select employee_id from employees where hire_date <= toDate('2025-03-31') and (fire_date is null or fire_date >= toDate('2025-03-01')) ),
last_event as ( select employee_id, event_time, event_type, salary, row_number() over ( partition by employee_id order by event_time desc ) as rn from employee_events )
select l.employee_id, l.salary, l.event_time from last_event l inner join active_in_march a on l.employee_id = a.employee_id where l.rn = 1 and l.event_type = 'salary_change' and l.salary > 200000
🧠 Как здесь думаем:
Сначала отдельно определяем сотрудников, которые пересекались с мартом 2025.
Логика такая: если сотрудник нанят не позже 31 марта 2025 и уволен либо после 1 марта 2025, либо вообще не уволен, значит он работал в марте ✅
Это классическая проверка пересечения интервалов.
Дальше по таблице employee_events ищем последнее событие по каждому сотруднику. Для этого используем:
• partition by employee_id • order by event_time desc • row_number()
Строка с rn = 1 — это последнее событие сотрудника.
После этого оставляем только тех, у кого:
• последнее событие = salary_change • salary > 200000
⚠️ Где можно ошибиться:
Неправильно проверить “работал в марте”
Частая ошибка — фильтровать только тех, кто был нанят именно в марте или уволен именно в марте.
Но нам нужны все, кто хотя бы частично работал в этом месяце. То есть проверяем именно пересечение интервала работы с мартом.
Взять последнее salary_change, а не последнее событие вообще
По условию нужно: “последнее событие — salary_change”
Это значит, что если после salary_change был, например, transfer, такой сотрудник уже не подходит ❌
Не продумать дедуп событий
Если у сотрудника много событий, простой join без оконной функции даст несколько строк. Поэтому здесь нужна явная дедупликация через row_number().
💡 Если у двух событий одного сотрудника одинаковый event_time, лучше добавить дополнительный tie-breaker в order by. Например, event_id, если он есть. Иначе “последнее” событие может определяться неоднозначно.
Например так:
row_number() over ( partition by employee_id order by event_time desc, event_id desc ) as rn
🎯 Вывод:
Это хорошая задача на 3 вещи сразу:
• интервалы дат • дедупликацию событий • точную бизнес-логику “последнего состояния”
Здесь важно не просто найти salary_change, а доказать, что это именно последнее событие сотрудника.
Именно на таких деталях чаще всего и ломается логика запроса 👌