На основе примера: Получаем актуальные данные о сотрудниках и должностях
В этой статье мы разберем практический пример SQL-запроса, который извлекает данные о сотрудниках и их должностях с использованием оператора LEFT JOIN. Вы научитесь правильно соединять таблицы, фильтровать данные по датам и учитывать статусы записей для получения только актуальной информации.
Структура таблиц и их взаимосвязи
Перед написанием запроса важно понимать, с какими таблицами мы работаем и как они связаны между собой:
-
Таблица
employees— содержит основные данные о сотрудниках:-
Идентификатор сотрудника
-
Фамилия и имя
-
Электронная почта
-
Статус активности (
is_active)
-
-
Таблица
positions— справочник должностей:-
Идентификатор должности
-
Название должности
-
Статус активности позиции
-
-
Таблица
positions_by_date— связующая таблица, которая определяет:-
Какой сотрудник (
employee_id) -
В какой должности (
position_id) -
Находился/находится в определенный период (
date_start,date_finish)
-
Пошаговый разбор SQL-запроса
Шаг 1: Определение структуры выборки (SELECT)
Начинаем с определения, какие данные мы хотим получить:
SELECT p.position_name AS "Должность", CONCAT(e.last_name, ' ', e.first_name) AS "ФИО сотрудника", e.email AS "Email"
Что здесь происходит:
-
Выбираем название должности из таблицы
positions -
Объединяем фамилию и имя сотрудника в одно поле через пробел
-
Добавляем email сотрудника
-
Используем алиасы (
pдля positions,eдля employees) для удобства
Шаг 2: Первый LEFT JOIN — присоединение таблицы назначений
FROM positions p LEFT JOIN positions_by_date pbd ON p.id = pbd.position_id
Ключевой момент:
Мы начинаем с таблицы должностей (positions) как основной (левой таблицы). LEFT JOIN гарантирует, что в результат попадут ВСЕ должности, даже если на них в данный момент никто не назначен.
Шаг 3: Второй LEFT JOIN — присоединение данных о сотрудниках
LEFT JOIN employees e ON pbd.employee_id = e.id
Важно: Этот JOIN также использует LEFT JOIN, что позволяет сохранить в результате все должности из предыдущего шага, даже если для них нет сотрудника в таблице назначений.
Шаг 4: Фильтрация по актуальным периодам (WHERE)
WHERE pbd.date_start <= CURRENT_DATE AND (pbd.date_finish IS NULL OR pbd.date_finish > CURRENT_DATE)
Эта часть запроса отвечает за актуальность данных:
-
date_start <= CURRENT_DATE— должность уже началась -
date_finish > CURRENT_DATE— должность еще не закончилась -
OR date_finish IS NULL— учитывает бессрочные назначения
Шаг 5: Учет активности сотрудников и должностей
AND e.is_active = true AND p.is_active = true
Дополнительные условия, которые исключают из результатов:
-
Уволенных сотрудников (
is_active = false) -
Удаленные или неактивные должности
Полный запрос
SELECT p.position_name AS "Должность", CONCAT(e.last_name, ' ', e.first_name) AS "ФИО сотрудника", e.email AS "Email" FROM positions p LEFT JOIN positions_by_date pbd ON p.id = pbd.position_id LEFT JOIN employees e ON pbd.employee_id = e.id WHERE pbd.date_start <= CURRENT_DATE AND (pbd.date_finish IS NULL OR pbd.date_finish > CURRENT_DATE) AND e.is_active = true AND p.is_active = true;
Что мы получим в результате?
Типичные сценарии вывода:
-
Должность с назначенным активным сотрудником:
Должность: Senior Developer ФИО сотрудника: Иванов Иван Email:
Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в браузере должен быть включен Javascript. -
Вакантная должность (есть должность, но нет сотрудника):
Должность: Project Manager ФИО сотрудника: NULL Email: NULL
-
Записи, которые НЕ попадут в результат:
-
Должность с уволенным сотрудником
-
Неактивная (удаленная) должность
-
Назначения, период которых еще не начался или уже завершился
-
Когда использовать LEFT JOIN?
LEFT JOIN применяется в ситуациях, когда необходимо:
-
Получить ВСЕ записи из основной таблицы, даже если в связанных таблицах нет соответствующих данных
-
Проанализировать заполненность данных (например, найти вакантные должности)
-
Сохранить целостность данных при наличии необязательных связей
Практическая ценность запроса
Данный запрос решает несколько важных бизнес-задач:
-
Актуальный штатный состав — всегда видно, какие должности заняты, а какие вакантны
-
Контроль периодов работы — автоматическое исключение исторических данных
-
Учет статусов — фильтрация только по действующим сотрудникам и должностям
-
Подготовка данных для отчетов — структурированная информация для кадрового учета
Рекомендации по использованию
-
Для повышения производительности создайте индексы на полях, используемых в JOIN и WHERE:
-
positions_by_date.position_id -
positions_by_date.employee_id -
positions_by_date.date_start,positions_by_date.date_finish
-
-
Для расширения функциональности можно добавить:
-
Сортировку по названию должности или ФИО
-
Группировку для статистики (сколько должностей вакантно)
-
Дополнительные поля (дата найма, отдел)
-
-
Для отладки временно убирайте условия WHERE, чтобы увидеть полную картину данных.
Этот запрос — отличная основа для построения различных отчетов в системе управления персоналом. Он демонстрирует, как правильно комбинировать JOIN-операции с фильтрацией по датам и статусам для получения бизнес-значимых результатов.
Чтобы увидеть запрос в действии, с пошаговым выполнением и визуализацией результатов каждого этапа, посмотрите наше видео-руководство. В нем мы наглядно показываем, как изменяется результат при добавлении каждого условия, и разбираем типичные ошибки, которые допускают новички при работе с LEFT JOIN.
Статья подготовлена по материалам обучающего видео для вашего удобства.