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