Как получить статус сотрудника на каждый день месяца в запросе 1С

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

При разработке отчетов, таких как «Табель учета рабочего времени» или специфических печатных форм в 1С:Управление торговлей 11, часто возникает необходимость получить состояние сотрудника (например, «Работает» или «Уволен») не на конкретную дату, а в динамике — на каждый день выбранного периода. Стандартная виртуальная таблица СрезПоследних отлично работает для получения данных на одну точку времени, но когда нам нужна выборка за 30-31 день для списка сотрудников, обычного обращения к ней становится недостаточно. Разберем подробно, как решить эту задачу эффективно.

Почему нельзя использовать стандартный СрезПоследних в цикле или простом соединении

Основная проблема заключается в том, что виртуальная таблица СрезПоследних принимает в качестве параметра одну дату. Если мы попытаемся соединить таблицу всех дней месяца с этой виртуальной таблицей, мы получим данные только на момент «сейчас» или на конец месяца, а не на каждый конкретный день. Проанализируем ситуацию: если сотрудник был уволен 15-го числа, то на 14-е число запрос должен выдать статус «Работает», а на 16-е — «Уволен». Чтобы добиться этого внутри одного запроса без обращения к базе в цикле, нам необходимо реализовать алгоритм «среза на каждую дату» самостоятельно.

Шаг 1. Формирование «сетки» данных

Для начала нам необходимо подготовить фундамент — таблицу, в которой будут перечислены все интересующие нас сотрудники и все даты месяца. Рассмотрим, как это сделать. Мы можем взять даты из существующего документа (например, Табеля) или сформировать их программно. В нашем примере воспользуемся данными из табличной части документа, как это предлагалось в исходном вопросе.

Создадим временную таблицу ВТ_СотрудникиИДаты. Она будет содержать уникальные пары «Сотрудник — Дата»:


ВЫБРАТЬ
    Табель.Сотрудник КАК Сотрудник,
    Табель.Дата КАК Дата
ПОМЕСТИТЬ ВТ_СотрудникиИДаты
ИЗ
    Документ.ЗП_Т_ТабельУчетаРабочегоВремени.Состав КАК Табель
ГДЕ
    Табель.Ссылка = &Ссылка
СГРУППИРОВАТЬ ПО
    Табель.Сотрудник,
    Табель.Дата
;

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

Шаг 2. Поиск актуального периода в регистре (Ручной срез последних)

Теперь для каждой даты из нашей сетки нам нужно найти запись в регистре сведений Кадры, которая была актуальна именно в этот момент. Актуальной считается запись, период которой меньше или равен нашей дате, и при этом является максимальным среди всех таких записей. Выясним, как это реализовать через ЛЕВОЕ СОЕДИНЕНИЕ.


ВЫБРАТЬ
    Сетка.Сотрудник КАК Сотрудник,
    Сетка.Дата КАК Дата,
    МАКСИМУМ(РегистрКадры.Период) КАК ПериодЗаписи
ПОМЕСТИТЬ ВТ_МаксимальныеПериоды
ИЗ
    ВТ_СотрудникиИДаты КАК Сетка
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Кадры КАК РегистрКадры
        ПО Сетка.Сотрудник = РегистрКадры.ФизЛицо
        И Сетка.Дата >= РегистрКадры.Период
СГРУППИРОВАТЬ ПО
    Сетка.Сотрудник,
    Сетка.Дата
;

В этом пакете запроса мы сопоставляем каждую дату сотрудника со всеми записями регистра, которые произошли «до» или «в» эту дату. Группировка по сотруднику и дате с функцией МАКСИМУМ(Период) позволяет нам вычислить точный момент времени последнего изменения статуса для каждого дня.

Шаг 3. Получение финальных данных (статуса увольнения)

Имея таблицу соответствия «Сотрудник — Дата — Период последней записи», мы можем легко получить значение ресурса Уволен. Для этого соединим полученную временную таблицу с реальной таблицей регистра сведений.


ВЫБРАТЬ
    МаксПериоды.Сотрудник КАК Сотрудник,
    МаксПериоды.Дата КАК Дата,
    ЕСТЬNULL(РегистрКадры.Уволен, ЛОЖЬ) КАК Уволен,
    ВЫБОР
        КОГДА РегистрКадры.Уволен ТОГДА "Уволен"
        ИНАЧЕ "Работает"
    КОНЕЦ КАК СтатусТекстом
ИЗ
    ВТ_МаксимальныеПериоды КАК МаксПериоды
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Кадры КАК РегистрКадры
        ПО МаксПериоды.Сотрудник = РегистрКадры.ФизЛицо
        И МаксПериоды.ПериодЗаписи = РегистрКадры.Период
;

Обратите внимание на использование функции ЕСТЬNULL. Если сотрудник еще не имеет записей в регистре на определенную дату (например, дата в сетке раньше даты приема), соединение вернет NULL. В таких случаях логично считать его либо не принятым, либо не уволенным, в зависимости от бизнес-логики вашей системы.

Альтернативный метод: Интервальный подход

Если сотрудников много, а период отчета большой, метод с МАКСИМУМ(Период) может работать медленно. Рассмотрим более оптимизированный способ — формирование интервалов. Идея заключается в том, чтобы для каждой записи регистра заранее вычислить «Дату завершения» (период следующей записи минус одна секунда).

Алгоритм интервалов выглядит так:

  1. Выбираем все записи регистра по нужным сотрудникам.
  2. Для каждой записи находим минимальный период следующей записи того же сотрудника.
  3. Если следующей записи нет, устанавливаем дату окончания в далекое будущее (3999 год).
  4. Соединяем нашу сетку дат с этой таблицей интервалов по условию: Дата МЕЖДУ ДатаНачала И ДатаОкончания.

Такой подход позволяет избежать тяжелых группировок МАКСИМУМ на больших объемах данных и часто используется в типовых конфигурациях 1С (например, в ЗУП 3.1).

Особенности учета «Физлицо» vs «Сотрудник»

В процессе реализации мы должны учитывать архитектуру УТ 11. Если ваш регистр самописный и использует измерение ФизЛицо, помните о ситуации с совместителями. Один человек может быть уволен по одной должности, но продолжать работать по другой. Как было отмечено в обсуждении, если один и тот же человек (ФизЛицо) увольняется и принимается снова в одном месяце, запрос по ФизЛицу может выдать некорректные данные, если в регистре нет разреза по документам приема или уникальным ссылкам справочника Сотрудники.

Рекомендация: Всегда проверяйте, достаточно ли измерений в вашем регистре для однозначного определения статуса. Если возможны повторные приемы, обязательно добавляйте измерение Сотрудник или Организация.

Использование СКД для упрощения задачи

Если ваша задача — построить отчет, а не просто получить таблицу в коде, можно воспользоваться механизмом Системы компоновки данных (СКД). В настройках ролей полей компоновки есть возможность указать роль «Период». При правильной настройке дополнения периодов и использовании виртуальных таблиц, СКД сама может «растянуть» последнее известное значение на все пустые даты, где не было движений. Это значительно сокращает объем написанного вручную кода запроса, перекладывая задачу формирования сетки на движок платформы.

Разберем, что мы получили в итоге: мы рассмотрели структуру пакета запроса, который последовательно формирует список дат, находит для каждой даты точку актуальности в истории изменений и сопоставляет её с конкретными значениями статуса. Этот метод является универсальным и применим к любым периодическим регистрам сведений в 1С.

← На главную