При работе с регистрами сведений в системе «1С:Предприятие 8» разработчики часто сталкиваются с ситуацией, когда стандартная виртуальная таблица СрезПоследних возвращает гораздо больше записей, чем ожидалось. Особенно остро эта проблема проявляется в кадровых регистрах, таких как СостоянияСотрудников. В этой статье мы подробно разберем, почему так происходит, проанализируем технические нюансы работы платформы и рассмотрим правильные способы получения данных на конкретную дату.
Первое, что нам необходимо уяснить: виртуальная таблица СрезПоследних работает в разрезе всех измерений регистра. Это фундаментальное правило, которое часто забывается при проектировании структуры метаданных. Если вы добавили в регистр дополнительное измерение (например, Год, Организация или пользовательское поле Дата), система будет искать последнюю запись для каждой уникальной комбинации этих значений.
Рассмотрим ситуацию: у сотрудника Иванова в регистре есть две записи. Одна с измерением Год = 2023, другая — с Год = 2024. С точки зрения платформы, это две разные аналитики. При попытке получить срез последних на текущую дату, система вернет обе записи, так как каждая из них является «последней» для своего набора измерений. Именно это автор темы и наблюдал в своих результатах — визуальные «дубли» по сотруднику на самом деле являются уникальными строками в разрезе измерений.
Вторая важная деталь заключается в том, что регистр СостоянияСотрудников (особенно в типовых конфигурациях вроде ЗУП 3.1 или ERP) по своей сути является интервальным. В отличие от простых периодических регистров, где состояние считается актуальным с момента записи и до появления следующей, здесь состояние часто ограничено конкретным периодом: Период (дата начала) и ДействуетДо (дата окончания).
Использование СрезаПоследних для таких данных не всегда корректно. Виртуальная таблица не знает о существовании ресурса или реквизита ДействуетДо. Она просто берет самую свежую запись по дате. Но что, если эта «самая свежая» запись уже завершилась? Например, сотрудник был в отпуске с 01.01 по 10.01, а мы делаем запрос на 15.01. Срез последних вернет запись об отпуске, хотя фактически на 15.01 сотрудник уже может быть в другом состоянии или просто работать.
Наиболее надежным способом получения состояния сотрудника является прямой запрос к физической таблице регистра с проверкой вхождения искомой даты в интервал. Разберем этот метод подробно. Нам нужно отобрать записи, где дата анализа больше или равна дате начала и меньше или равна дате окончания.
При этом важно учитывать «пустые» даты окончания (когда состояние еще действует и дата завершения не установлена). В 1С пустая дата — это 01.01.0001. Для корректного сравнения мы будем использовать конструкцию ВЫБОР, заменяя пустую дату на максимально возможную в системе.
Проанализируем пример кода:
ВЫБРАТЬ
ИзмеренияДаты.Сотрудник КАК Сотрудник,
ИзмеренияДаты.Период КАК Период,
Состояния.Состояние КАК Состояние,
Состояния.ВидВремени КАК ВидВремени
ИЗ
ВТОписаниеФильтра КАК ИзмеренияДаты
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СостоянияСотрудников КАК Состояния
ПО ИзмеренияДаты.Сотрудник = Состояния.Сотрудник
И (ИзмеренияДаты.Период МЕЖДУ Состояния.Период И
ВЫБОР
КОГДА Состояния.ДействуетДо = ДАТАВРЕМЯ(1, 1, 1)
ТОГДА ДАТАВРЕМЯ(3999, 12, 31)
ИНАЧЕ КОНЕЦПЕРИОДА(Состояния.ДействуетДо, ДЕНЬ)
КОНЕЦ)
Почему этот подход лучше?
NULL при левом соединении).Если структура регистра «испорчена» лишними измерениями, и вы не можете их удалить, а СрезПоследних продолжает выдавать дубли, можно прибегнуть к классическому методу получения последних данных через МАКСИМУМ(Период). Этот метод гарантирует, что для каждого сотрудника будет выбрана строго одна запись — та, что была внесена последней.
Рассмотрим реализацию этого алгоритма:
ВЫБРАТЬ
Состояния.Сотрудник КАК Сотрудник,
Состояния.Период КАК Период,
Состояния.Состояние КАК Состояние
ИЗ
РегистрСведений.СостоянияСотрудников КАК Состояния
ГДЕ
Состояния.Период В (
ВЫБРАТЬ
МАКСИМУМ(Вложенный.Период)
ИЗ
РегистрСведений.СостоянияСотрудников КАК Вложенный
ГДЕ
Вложенный.Сотрудник = Состояния.Сотрудник
И Вложенный.Период <= &НаДату
)
Этот способ более ресурсозатратный для базы данных, чем работа с виртуальной таблицей, но он является «спасательным кругом», когда стандартные механизмы не справляются из-за специфической архитектуры регистра.
Разберем по шагам, как минимизировать ошибки при получении состояний в будущем:
Сотрудник. Все остальное (организация, подразделение, график) должно быть ресурсами или реквизитами.СостоянияСотрудников, рассмотрите возможность вызова функций из общих модулей, таких как СостоянияСотрудников.ДанныеСостоянийСотрудников.01.01.0001). В запросах заменяйте ее на 31.12.3999, чтобы операторы сравнения работали предсказуемо.Подводя итог, можно сказать, что «Срез последних» — это мощный инструмент, но он требует строгого соблюдения правил проектирования регистров. Если ваш регистр превратился в «интервальный» или оброс лишними измерениями, не бойтесь переходить на прямые запросы к физическим таблицам. Это сделает ваш код более прозрачным, а результат — предсказуемым.