Как правильно получить кадровые данные сотрудников на определенную дату из регистров сведений?

Программист 1С v8.3 (Управляемые формы) 1С:Зарплата и Управление Персоналом
← На главную

При разработке отчетов или обработок в системах на базе 1С:Предприятие (таких как ЗУП 3.1, ERP или Комплексная автоматизация) часто возникает задача получения среза кадровых данных на конкретную дату. Основная сложность заключается в том, что информация распределена по нескольким регистрам сведений, а данные в них являются периодическими. Нам необходимо собрать воедино сотрудника, его подразделение, должность, количество ставок, вид занятости, дату приема и текущее состояние (работает, в отпуске, на больничном).

Рассмотрим подробнее, как построить эффективный запрос, избежать дублирования записей и правильно отсечь сотрудников, которые еще не приняты на работу или уже уволены.

Использование виртуальных таблиц для получения актуальных данных

Для работы с периодическими регистрами сведений в 1С предусмотрены виртуальные таблицы СрезПоследних. Это наиболее оптимальный механизм, так как платформа берет на себя задачу поиска последней записи на указанный момент времени. Проанализируем типичную ошибку начинающих разработчиков: попытку найти максимум по полю Период через вложенные запросы. Это существенно замедляет работу системы. Вместо этого мы будем использовать параметры виртуальных таблиц.

Разберем первый шаг — получение основных данных из регистра КадроваяИсторияСотрудников. Нам нужно получить состояние сотрудника на дату среза:


ВЫБРАТЬ
    КадроваяИстория.Сотрудник КАК Сотрудник,
    КадроваяИстория.Подразделение КАК Подразделение,
    КадроваяИстория.Должность КАК Должность,
    КадроваяИстория.КоличествоСтавок КАК КоличествоСтавок,
    КадроваяИстория.ВидСобытия КАК ВидСобытия,
    КадроваяИстория.Период КАК ПериодПоследнегоСобытия
ПОМЕСТИТЬ ВтПоследниеДанные
ИЗ
    РегистрСведений.КадроваяИсторияСотрудников.СрезПоследних(&ДатаСреза, ) КАК КадроваяИстория
ГДЕ
    НЕ КадроваяИстория.ВидСобытия = ЗНАЧЕНИЕ(Перечисление.ВидыКадровыхСобытий.Увольнение)
ИНДЕКСИРОВАТЬ ПО
    Сотрудник;

Обратите внимание на использование условия в секции ГДЕ. Мы исключаем уволенных сотрудников сразу в первой временной таблице. Также крайне важно использовать ИНДЕКСИРОВАТЬ ПО для временных таблиц, если в дальнейшем планируется их соединение. Это значительно повышает производительность запроса на больших базах данных.

Как корректно получить дату приема на работу

Одной из главных проблем, описанных в теме, является получение даты приема. Если мы просто возьмем поле Период из среза последних, мы получим дату последнего кадрового изменения (например, перемещения), а не дату фактического приема. Чтобы получить именно дату приема, нам нужно обратиться к тому же регистру, но с фильтром по виду события.

Рассмотрим, как это реализовать:


ВЫБРАТЬ
    Приемы.Сотрудник КАК Сотрудник,
    Приемы.Период КАК ДатаПриема
ПОМЕСТИТЬ ВтДатыПриема
ИЗ
    РегистрСведений.КадроваяИсторияСотрудников.СрезПоследних(&ДатаСреза, ВидСобытия = ЗНАЧЕНИЕ(Перечисление.ВидыКадровыхСобытий.Прием)) КАК Приемы
ИНДЕКСИРОВАТЬ ПО
    Сотрудник;

Здесь мы используем второй параметр виртуальной таблицы для фильтрации. Выясним причину, по которой у автора вопроса появлялась некорректная дата "25.10.2010". Это часто происходит из-за использования ПОЛНОЕ СОЕДИНЕНИЕ или неверного сопоставления периодов. Используя СрезПоследних с конкретным отбором по событию Прием, мы гарантируем получение правильной даты начала работы.

Сборка итоговой таблицы данных

Теперь проанализируем ситуацию с остальными регистрами: ВидыЗанятостиСотрудников и СостоянияСотрудников. Нам необходимо соединить все полученные данные в одну выборку. Посмотрим на пример итогового запроса:


ВЫБРАТЬ
    Данные.Сотрудник КАК Сотрудник,
    Данные.Подразделение КАК Подразделение,
    Данные.Должность КАК Должность,
    Данные.КоличествоСтавок КАК КоличествоСтавок,
    ДатыПриема.ДатаПриема КАК ДатаПриема,
    ВидыЗанятости.ВидЗанятости КАК ВидЗанятости,
    Состояния.Состояние КАК Состояние
ИЗ
    ВтПоследниеДанные КАК Данные
    ЛЕВОЕ СОЕДИНЕНИЕ ВтДатыПриема КАК ДатыПриема
        ПО Данные.Сотрудник = ДатыПриема.Сотрудник
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ВидыЗанятостиСотрудников.СрезПоследних(&ДатаСреза, ) КАК ВидыЗанятости
        ПО Данные.Сотрудник = ВидыЗанятости.Сотрудник
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СостоянияСотрудников.SрезПоследних(&ДатаСреза, ) КАК Состояния
        ПО Данные.Сотрудник = Состояния.Сотрудник
ГДЕ
    НЕ ДатыПриема.ДатаПриема ЕСТЬ NULL

Разберем по шагам, почему выбрана такая структура:

  1. Левое соединение: Мы используем его для всех вспомогательных таблиц. Основным источником является ВтПоследниеДанные, где уже отсечены уволенные сотрудники.
  2. Фильтрация по дате приема: Если ДатыПриема.ДатаПриема возвращает NULL, это означает, что на указанную дату сотрудник еще не был принят (или нет записи о приеме). Условие НЕ ... ЕСТЬ NULL позволяет нам вывести только тех, кто уже фактически числится в штате.
  3. Состояния: Регистр СостоянияСотрудников покажет нам, находится ли человек в отпуске или на больничном. Это периодический регистр, и СрезПоследних здесь работает идеально.

Программный метод получения кадровых данных (ЗУП 3.1)

Если ваша задача выполняется в рамках типовой конфигурации (ЗУП 3.1 или ERP), мы крайне рекомендуем использовать встроенный программный интерфейс (API). В этих конфигурациях существует мощный механизм — программный модуль КадровыйУчет. Функция КадровыеДанныеСотрудников позволяет получить все необходимые сведения одной строкой кода, при этом система сама оптимизирует запросы и учитывает все нюансы (например, работу по внутреннему совместительству).

Посмотрим на пример использования:


СписокПолей = "Сотрудник,Подразделение,Должность,ВидЗанятости,КоличествоСтавок,ДатаПриема";
ТаблицаДанных = КадровыйУчет.КадровыеДанныеСотрудников(Истина, МассивСотрудников, СписокПолей, ДатаСреза);

Этот метод предпочтителен по нескольким причинам:

Резюме и рекомендации

Подводя итог нашему анализу, выделим ключевые моменты для успешного решения задачи:

Во-первых, всегда используйте виртуальные таблицы СрезПоследних с параметром даты. Это исключает необходимость вручную фильтровать периоды и искать максимальные даты.

Во-вторых, для получения даты приема делайте отдельное соединение с тем же регистром кадровой истории, но с фильтром по значению Перечисление.ВидыКадровыхСобытий.Прием.

В-третьих, если вы работаете в современной типовой конфигурации, рассмотрите возможность использования функции КадровыйУчет.КадровыеДанныеСотрудников. Это сэкономит ваше время и обеспечит высокую стабильность работы системы.

Правильно построенный запрос не только решает текущую проблему с выводом дат, но и обеспечивает высокую производительность отчета, что критически важно при работе с большим штатом сотрудников (от нескольких тысяч человек и выше).

← На главную