При разработке отчетов и механизмов проведения документов в 1С часто возникает ситуация, когда несколько документов формируют движения по одному и тому же периодическому регистру сведений на одну дату или с одинаковым значением поля Период. При обращении к виртуальной таблице СрезПоследних разработчик ожидает получить данные документа, проведенного последним по физическому времени, но виртуальная таблица возвращает более раннее значение. Проанализируем, почему так происходит и как получить корректный результат.
Для подчиненных регистратору регистров сведений в платформе 1С существует строго определенный порядок формирования первичного ключа и вычисления среза последних. Внутренний состав ключа строится по следующему приоритету:
Период самой записи регистра. Если одна запись сформирована датой следующего дня, она всегда будет приоритетнее записи текущего дня, независимо от времени проведения документа.Период у записей совпадают, актуальность определяется ссылкой на документ-регистратор. В СУБД ссылки сравниваются по их бинарному уникальному идентификатору (GUID). Порядок генерации GUID не зависит от времени создания документа в интерфейсе, поэтому более поздний по факту проведения документ может проиграть в сравнении, если его внутренний идентификатор оказался меньше.Таким образом, виртуальная таблица СрезПоследних не анализирует реквизит Регистратор.Дата, если поле Период записи заполнено без учета времени (например, 00:00:00). Сравнение происходит исключительно по внутренним системным полям.
Если изменить логику заполнения поля Период нельзя, самым надежным решением для отчета является отказ от виртуальной таблицы среза последних в пользу выборки из физической таблицы РегистрСведений.ИмяРегистра. В этом случае мы получаем возможность явно отсортировать записи по дате документа-регистратора.
Посмотрим на пример запроса для получения последнего значения по конкретному объекту:
ВЫБРАТЬ ПЕРВЫЕ 1
ТаблицаРегистра.Период КАК Период,
ТаблицаРегистра.Регистратор КАК Регистратор,
ТаблицаРегистра.Значение КАК Значение
ИЗ
РегистрСведений.ЦеныНоменклатуры КАК ТаблицаРегистра
ГДЕ
ТаблицаРегистра.Номенклатура = &Номенклатура
И ТаблицаРегистра.Период <= &ПериодОтбора
УПОРЯДОЧИТЬ ПО
ТаблицаРегистра.Период УБЫВ,
ТаблицаРегистра.Регистратор.Дата УБЫВ,
ТаблицаРегистра.НомерСтроки УБЫВ
Если необходимо получить срез последних сразу по списку объектов или по всей таблице, разберем построение запроса с использованием группировки по максимальной дате регистратора:
ВЫБРАТЬ
Максимумы.Номенклатура КАК Номенклатура,
ТаблицаРегистра.Значение КАК Значение
ИЗ
(ВЫБРАТЬ
Регистр.Номенклатура КАК Номенклатура,
МАКСИМУМ(Регистр.Регистратор.Дата) КАК МаксДата
ИЗ
РегистрСведений.ЦеныНоменклатуры КАК Регистр
ГДЕ
Регистр.Период <= &ПериодОтбора
СГРУППИРОВАТЬ ПО
Регистр.Номенклатура) КАК Максимумы
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры КАК ТаблицаРегистра
ПО Максимумы.Номенклатура = ТаблицаРегистра.Номенклатура
И Максимумы.МаксДата = ТаблицаРегистра.Регистратор.Дата
Если срез последних рассчитывается на момент проведения конкретного документа, в параметры виртуальной таблицы среза можно передавать не дату, а объект Граница с типом МоментВремени. Это гарантирует, что движения документов, расположенных на временной оси позже текущей позиции, не попадут в выборку.
Рассмотрим пример установки параметра в кодовой части:
ГраницаОтбора = Новый Граница(ДокументСсылка.МоментВремени(), ВидГраницы.Включая);
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Срез.Номенклатура КАК Номенклатура,
| Срез.Значение КАК Значение
|ИЗ
| РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&ПериодСреза, ) КАК Срез";
Запрос.УстановитьПараметр("ПериодСреза", ГраницаОтбора);
Результат = Запрос.Выполнить();
Для предотвращения конфликтов в типовых и нетиповых конфигурациях рекомендуется применять архитектурные решения на этапе проектирования:
АвтоВремя (например, в режим ТекущееИлиПоследнее или Последнее). Это выстроит документы в хронологическую цепочку с разницей в секундах, и их поле МоментВремени будет уникальным и последовательным.Период набора записей совпадало с датой документа-регистратора с точностью до секунд.