При работе с кадровой отчетностью в конфигурациях «1С:Зарплата и управление персоналом» часто возникает задача проанализировать подразделения не только по наличию в них определенных сотрудников, но и по их отсутствию. Типичный пример — вывод списка подразделений, где на данный момент никто не находится в декретном отпуске (отпуске по уходу за ребенком). Сложность здесь заключается в том, что стандартные запросы к регистрам сведений выдают только те подразделения, по которым есть движения. Если сотрудников в декрете нет, подразделение просто не попадет в выборку.
В этой статье мы подробно разберем, как правильно составить запрос, чтобы получить полную картину, включая подразделения с нулевым количеством декретников.
Рассмотрим ситуацию: если мы будем строить запрос напрямую от регистра РегистрСведений.СостоянияСотрудников или РегистрСведений.КадроваяИсторияСотрудников, мы получим список тех, кто числится в системе. Если в подразделении «Отдел маркетинга» нет ни одного человека в декрете, в этих регистрах просто не будет записей с соответствующим состоянием для этого подразделения.
Для решения этой задачи мы применим классический метод «Левого соединения со справочником». Суть метода заключается в следующем:
Подразделения (или ПодразделенияОрганизаций), присоединив к нему нашу временную таблицу.NULL), и есть искомые нами подразделения.Проанализируем, какие данные нам нужны. Состояние сотрудника фиксируется в регистре СостоянияСотрудников. Нам важно получить актуальное состояние на определенную дату, поэтому используем СрезПоследних. Также нам понадобится подразделение из кадровой истории.
Посмотрим на пример формирования временной таблицы:
ВЫБРАТЬ
СостоянияСотрудниковСрезПоследних.Сотрудник КАК Сотрудник,
КадроваяИсторияСотрудниковСрезПоследних.Подразделение КАК Подразделение
ПОМЕСТИТЬ ВТ_СотрудникиВДекрете
ИЗ
РегистрСведений.СостоянияСотрудников.СрезПоследних(&ДатаОтчета, ) КАК СостоянияСотрудниковСрезПоследних
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КадроваяИсторияСотрудников.СрезПоследних(&ДатаОтчета, ) КАК КадроваяИсторияСотрудниковСрезПоследних
ПО СостоянияСотрудниковСрезПоследних.Сотрудник = КадроваяИсторияСотрудниковСрезПоследних.Сотрудник
ГДЕ
СостоянияСотрудниковСрезПоследних.Состояние = ЗНАЧЕНИЕ(Перечисление.СостоянияСотрудника.ОтпускПоУходуЗаРебенком)
;
В данном фрагменте мы используем ВНУТРЕННЕЕ СОЕДИНЕНИЕ, так как нам нужны только те сотрудники, у которых одновременно есть и состояние декрета, и актуальная запись в кадровой истории. Обратите внимание, что условие на состояние ОтпускПоУходуЗаРебенком позволяет нам отсечь всех остальных работающих сотрудников.
Теперь рассмотрим основную часть запроса. Нам нужно взять все подразделения из справочника и «наложить» на них данные из нашей временной таблицы ВТ_СотрудникиВДекрете.
ВЫБРАТЬ
Подразделения.Ссылка КАК Подразделение,
ЕСТЬNULL(ВТ_Декретники.Количество, 0) КАК КоличествоДекретников
ИЗ
Справочник.ПодразделенияОрганизаций КАК Подразделения
ЛЕВОЕ СОЕДИНЕНИЕ (
ВЫБРАТЬ
ВТ.Подразделение КАК Подразделение,
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ВТ.Сотрудник) КАК Количество
ИЗ
ВТ_СотрудникиВДекрете КАК ВТ
СГРУППИРОВАТЬ ПО
ВТ.Подразделение
) КАК ВТ_Декретники
ПО Подразделения.Ссылка = ВТ_Декретники.Подразделение
ГДЕ
НЕ Подразделения.ЭтоГруппа
И (Подразделения.Расформировано = ЛОЖЬ ИЛИ Подразделения.Расформировано ЕСТЬ NULL)
И ВТ_Декретники.Подразделение ЕСТЬ NULL
Разберем подробнее, что происходит в этом запросе:
Справочник.ПодразделенияОрганизаций. Это гарантирует, что в списке будут абсолютно все отделы организации.ЛЕВОЕ СОЕДИНЕНИЕ. Если в правой части (подзапрос с декретниками) нет записи для конкретного подразделения, 1С подставит NULL.ГДЕ мы накладываем критически важное условие: ВТ_Декретники.Подразделение ЕСТЬ NULL. Это и есть фильтр, который оставит нам только те подразделения, где сотрудников в декрете не обнаружено.Расформировано. Это поможет избежать вывода старых, неактуальных подразделений, которые уже не существуют, но хранятся в базе.Проанализируем ситуацию с выбором регистров. В современных конфигурациях (например, ЗУП 3.1) существует несколько способов получить состояние сотрудника. Один из наиболее эффективных — использование вспомогательного регистра ДанныеСостоянийСотрудников. В нем информация зачастую представлена в более развернутом и удобном для запросов виде.
Если вы используете РегистрСведений.СостоянияСотрудников.СрезПоследних, обязательно передавайте в параметры метода дату отчета (&Дата). Без этого 1С вернет срез на текущий момент времени (на «сейчас»), что может не соответствовать периоду, за который вы строите отчет.
Иногда пользователю требуется видеть не только пустые подразделения, но и полный список отделов с указанием количества декретников (где-то 5, где-то 0). В таком случае мы просто убираем условие ЕСТЬ NULL и используем функцию ЕСТЬNULL для вывода красивого нуля в отчете.
ВЫБРАТЬ
Подразделения.Наименование КАК ПодразделениеНаименование,
ЕСТЬNULL(ВТ_Декретники.Количество, 0) КАК Количество
ИЗ
Справочник.ПодразделенияОрганизаций КАК Подразделения
ЛЕВОЕ СОЕДИНЕНИЕ (
ВЫБРАТЬ
Подразделение КАК Подразделение,
КОЛИЧЕСТВО(Сотрудник) КАК Количество
ИЗ
ВТ_СотрудникиВДекрете
СГРУППИРОВАТЬ ПО
Подразделение
) КАК ВТ_Декретники
ПО Подразделения.Ссылка = ВТ_Декретники.Подразделение
ГДЕ
Подразделения.ЭтоГруппа = ЛОЖЬ
Важный совет: При работе с подразделениями всегда помните об иерархии. Если вам нужно проверить отсутствие декретников не только в конкретном отделе, но и во всей его «ветке» (включая подотделы), логика запроса усложнится. Потребуется использование оператора В ИЕРАРХИИ или предварительный обход дерева подразделений.
Мы выяснили, что для решения задачи вывода «пустых» подразделений нельзя ограничиваться только регистрами сведений. Основным ключом к решению является справочник Подразделений как ведущая таблица запроса. Комбинируя ЛЕВОЕ СОЕДИНЕНИЕ с проверкой на NULL, мы получаем надежный инструмент для поиска любых отсутствующих данных в системе, будь то подразделения без сотрудников в декрете, склады без остатков или клиенты без заказов.