Как правильно получить срез последних на Границу документа в регистре сведений

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

При разработке механизмов в 1С часто возникает задача получить данные из периодического регистра сведений в состоянии «на момент до проведения документа». Это критично для кадрового учета, расчета зарплаты или складских операций, когда нам нужно знать, какие значения (оклад, должность, цена) были актуальны непосредственно перед тем, как текущий документ внес свои изменения. Основным инструментом для этого является виртуальная таблица СрезПоследних и объект Граница. Однако программисты часто сталкиваются с тем, что запрос либо выдает неверные данные, либо вовсе не выполняется. Разберем детально, как решить эту задачу правильно.

Понятие Границы и Момента времени

Для начала проанализируем, почему обычная дата не подходит для решения задачи. Если мы передадим в параметры СрезПоследних просто дату документа, система вернет данные на конец указанной секунды. Если документ сам сделал запись в регистр в эту же секунду, его данные уже попадут в выборку. Чтобы «отсечь» движения самого документа, используется объект Граница.

Объект Граница позволяет указать системе, нужно ли включать записи, попадающие ровно на указанный момент, в результат запроса или нет. Для получения данных «до документа» мы используем ВидГраницы.Исключая.

Решение проблемы через правильный синтаксис

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

Проанализируем работающий вариант кода:


// Получаем необходимые данные документа
ДатаДокумента = Объект.Дата;
ДокументСсылка = Объект.Ссылка;

// Формируем объект Граница правильно
// Важно использовать конструктор МоментВремени явно
ГраницаСреза = Новый Граница(Новый МоментВремени(ДатаДокумента, ДокументСсылка), ВидГраницы.Исключая);

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

Запрос.УстановитьПараметр("ГраницаСреза", ГраницаСреза);
РезультатЗапроса = Запрос.Выполнить();

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

Влияние периодичности регистра на результат

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

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

Совет: Если вам важна точность до документа, всегда устанавливайте периодичность регистра По позиции регистратора.

Особенности работы в Консоли запросов

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

Если вы тестируете запрос в консоли:

Альтернативный метод получения данных (через физическую таблицу)

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


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

Однако стоит помнить, что прямое обращение к физической таблице лишает нас преимуществ оптимизации, которые предоставляет платформа для виртуальных таблиц. Поэтому использование СрезПоследних с правильно сконструированной Границей остается приоритетным вариантом.

Резюме для разработчика

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

  1. Всегда передавайте в конструктор Граница объект МоментВремени, созданный на основании даты и ссылки документа.
  2. Используйте ВидГраницы.Исключая, чтобы получить состояние регистра «до» текущего документа.
  3. Проверьте, что у регистра сведений установлена периодичность По позиции регистратора, если в системе возможны несколько движений в одну секунду по одним и тем же измерениям.
  4. Помните, что использование Границы в запросах — это стандартный механизм платформы, и при правильном синтаксисе он работает надежно и предсказуемо.
← На главную