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

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

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

Выясним причину: как платформа 1С определяет актуальность записи

Для подчиненных регистратору регистров сведений в платформе 1С существует строго определенный порядок формирования первичного ключа и вычисления среза последних. Внутренний состав ключа строится по следующему приоритету:

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

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

Способ 1. Запрос к реальной таблице регистра с сортировкой по дате регистратора

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

Посмотрим на пример запроса для получения последнего значения по конкретному объекту:


ВЫБРАТЬ ПЕРВЫЕ 1
	ТаблицаРегистра.Период КАК Период,
	ТаблицаРегистра.Регистратор КАК Регистратор,
	ТаблицаРегистра.Значение КАК Значение
ИЗ
	РегистрСведений.ЦеныНоменклатуры КАК ТаблицаРегистра
ГДЕ
	ТаблицаРегистра.Номенклатура = &Номенклатура
	И ТаблицаРегистра.Период <= &ПериодОтбора
УПОРЯДОЧИТЬ ПО
	ТаблицаРегистра.Период УБЫВ,
	ТаблицаРегистра.Регистратор.Дата УБЫВ,
	ТаблицаРегистра.НомерСтроки УБЫВ

Если необходимо получить срез последних сразу по списку объектов или по всей таблице, разберем построение запроса с использованием группировки по максимальной дате регистратора:


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

Способ 2. Использование объекта Граница и МоментВремени

Если срез последних рассчитывается на момент проведения конкретного документа, в параметры виртуальной таблицы среза можно передавать не дату, а объект Граница с типом МоментВремени. Это гарантирует, что движения документов, расположенных на временной оси позже текущей позиции, не попадут в выборку.

Рассмотрим пример установки параметра в кодовой части:


ГраницаОтбора = Новый Граница(ДокументСсылка.МоментВремени(), ВидГраницы.Включая);

Запрос = Новый Запрос;
Запрос.Текст = 
	"ВЫБРАТЬ
	|	Срез.Номенклатура КАК Номенклатура,
	|	Срез.Значение КАК Значение
	|ИЗ
	|	РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&ПериодСреза, ) КАК Срез";

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

Способ 3. Корректировка структуры регистра и позиционирования документов

Для предотвращения конфликтов в типовых и нетиповых конфигурациях рекомендуется применять архитектурные решения на этапе проектирования:

  1. Включение механизма «АвтоВремя»: если документы проводятся в пределах одних суток без ручного указания времени, следует настроить свойство документа АвтоВремя (например, в режим ТекущееИлиПоследнее или Последнее). Это выстроит документы в хронологическую цепочку с разницей в секундах, и их поле МоментВремени будет уникальным и последовательным.
  2. Добавление дополнительного измерения: если в пределах одной даты регистрируются разные логические события, в структуру регистра вводится измерение-разделитель (например, ссылка на документ-основание или перечисление типа операции). Это исключает замещение одной записи другой в срезе последних.
  3. Перевод регистра в режим «Периодический с точностью по позиции регистратора»: для подчиненных регистров рекомендуется контролировать, чтобы поле Период набора записей совпадало с датой документа-регистратора с точностью до секунд.
← На главную