Как посчитать employee turnover в SQL
Содержание:
Зачем turnover
Turnover (текучесть) — доля сотрудников, покинувших компанию за период. Главный HR-индикатор. Высокий turnover дорог: replacement cost = 50-200% годовой зарплаты. Низкий — здоровая культура, или признак того, что плохие performers не уходят. Идеально 8-15% для зрелых компаний, 20-30% для стартапов.
Формула
turnover_rate = leavers_in_period / average_headcount_in_periodaverage_headcount = (start + end) / 2 или среднее по дням. Период обычно — год.
Turnover в SQL
WITH period AS (
SELECT '2025-01-01'::DATE AS start_date, '2025-12-31'::DATE AS end_date
),
leavers AS (
SELECT employee_id
FROM employees
WHERE termination_date BETWEEN (SELECT start_date FROM period) AND (SELECT end_date FROM period)
),
start_hc AS (
SELECT COUNT(*) AS n
FROM employees
WHERE hire_date <= (SELECT start_date FROM period)
AND (termination_date IS NULL OR termination_date > (SELECT start_date FROM period))
),
end_hc AS (
SELECT COUNT(*) AS n
FROM employees
WHERE hire_date <= (SELECT end_date FROM period)
AND (termination_date IS NULL OR termination_date > (SELECT end_date FROM period))
)
SELECT
(SELECT COUNT(*) FROM leavers) AS leavers,
(SELECT n FROM start_hc) AS start_headcount,
(SELECT n FROM end_hc) AS end_headcount,
((SELECT n FROM start_hc) + (SELECT n FROM end_hc)) / 2.0 AS avg_headcount,
(SELECT COUNT(*) FROM leavers)::NUMERIC * 100
/ NULLIF(((SELECT n FROM start_hc) + (SELECT n FROM end_hc)) / 2.0, 0) AS turnover_pct;Voluntary vs involuntary
SELECT
CASE
WHEN termination_reason IN ('resignation', 'retirement') THEN 'voluntary'
WHEN termination_reason IN ('layoff', 'fired', 'performance') THEN 'involuntary'
ELSE 'other'
END AS turnover_type,
COUNT(*) AS leavers
FROM employees
WHERE termination_date BETWEEN '2025-01-01' AND '2025-12-31'
GROUP BY 1
ORDER BY leavers DESC;Voluntary turnover отражает engagement и компенсацию. Involuntary — performance management.
По департаментам
SELECT
department,
COUNT(*) FILTER (WHERE termination_date IS NOT NULL
AND termination_date BETWEEN '2025-01-01' AND '2025-12-31') AS leavers,
COUNT(*) FILTER (WHERE hire_date <= '2025-01-01'
AND (termination_date IS NULL OR termination_date > '2025-01-01')) AS start_hc,
COUNT(*) FILTER (WHERE termination_date IS NOT NULL
AND termination_date BETWEEN '2025-01-01' AND '2025-12-31')::NUMERIC * 100
/ NULLIF(COUNT(*) FILTER (WHERE hire_date <= '2025-01-01'
AND (termination_date IS NULL OR termination_date > '2025-01-01')), 0) AS turnover_pct
FROM employees
GROUP BY department
HAVING COUNT(*) FILTER (WHERE hire_date <= '2025-01-01') >= 10
ORDER BY turnover_pct DESC;Department с резко высоким turnover — investigate (плохой manager, культура).
Частые ошибки
Ошибка 1. Считать на end headcount, не average. Если компания быстро растёт, end > start, turnover занижен. Average правильнее.
Ошибка 2. Включать interns / contractors. Их «turnover» естественно высокий (контракт закончился). Сегментируйте.
Ошибка 3. Не различать voluntary/involuntary. Mass layoff в одну дату делает overall turnover ужасным. Сегментируйте — show обоснованную картину.
Ошибка 4. Annualize monthly без compound.
Annual turnover ≠ monthly × 12. Используйте 1 - (1 - monthly)^12.
Ошибка 5. Сравнивать без context. Tech industry 15-25% normal. Hospitality 50-100% norm. Без бенчмарка непонятно.
Связанные темы
- Как посчитать attrition by tenure в SQL
- Как посчитать headcount growth в SQL
- Как посчитать churn в SQL
- Как посчитать customer tenure в SQL
FAQ
Какой turnover норма?
Tech B2B 10-15%. Tech consumer 15-25%. Стартапы 20-30%.
Voluntary vs involuntary share?
Healthy: 70% voluntary, 30% involuntary.
Regret vs non-regret?
Regret = «жалко, что ушёл». Non-regret = performance-related. Считать отдельно.
Когда turnover — красный флаг?
Свыше 30% годовых для tech B2B. Свыше 25% в одной команде.
Replacement cost?
50-200% годовой зарплаты position. Включает рекрутинг, training, потеря productivity.