При выполнении свертки информационной базы 1С часто возникает необходимость перенести актуальные значения регистров сведений на дату окончания свертки (ввести начальные остатки или формировать срезы). Однако при анализе кода типовых обработок свертки можно заметить специфическое условие: запрос обращается к виртуальной таблице СрезПоследних, а затем выполняет левое соединение с виртуальной таблицей СрезПервых на начало следующего дня и отсекает записи с помощью условия ТабРегСрезПервых.Период ЕСТЬ NULL.
Рассмотрим подробно, для чего создана эта конструкция, в каких случаях она применяется и как особенности платформы 1С по работе с ключами уникальности влияют на логику свертки.
Проанализируем алгоритм, с помощью которого платформа собирает текст запроса для регистров сведений, подчиненных регистратору:
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| ЛОЖЬ КАК Активность,
| &ПериодЗаписи КАК Период,";
Для Каждого ТекИзмерение Из ТекРег.Измерения Цикл
Запрос.Текст = Запрос.Текст + "
| ТабРег." + ТекИзмерение.Имя + ",";
КонецЦикла;
Для Каждого ТекРесурс Из ТекРег.Ресурсы Цикл
Запрос.Текст = Запрос.Текст + "
| ТабРег." + ТекРесурс.Имя + " КАК " + ТекРесурс.Имя + ",";
КонецЦикла;
Для Каждого ТекРеквизит Из ТекРег.Реквизиты Цикл
Запрос.Текст = Запрос.Текст + "
| ТабРег." + ТекРеквизит.Имя + " КАК " + ТекРеквизит.Имя + ",";
КонецЦикла;
Запрос.Текст = Лев(Запрос.Текст, СтрДлина(Запрос.Текст)-1);
Запрос.Текст = Запрос.Текст + "
|ИЗ
| РегистрСведений." + ТекРег.Имя + ".СрезПоследних(&ДатаОст, ) КАК ТабРег";
Если (НЕ ТекРег.ПериодичностьРегистраСведений = Метаданные.СвойстваОбъектов.ПериодичностьРегистраСведений.ПозицияРегистратора) Тогда
Запрос.Текст = Запрос.Текст + "
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений." + ТекРег.Имя + ".СрезПервых(&ДатаОст, Период = НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(&ДатаОст, ДЕНЬ, 1), ДЕНЬ)) КАК ТабРегСрезПервых
| ПО ИСТИНА";
Для Каждого ТекИзмерение Из ТекРег.Измерения Цикл
Запрос.Текст = Запрос.Текст + "
| И ТабРег." + ТекИзмерение.Имя + " = ТабРегСрезПервых." + ТекИзмерение.Имя;
КонецЦикла;
Запрос.Текст = Запрос.Текст + "
|ГДЕ
| ТабРегСрезПервых.Период ЕСТЬ NULL";
КонецЕсли;
Запрос.УстановитьПараметр("ДатаОст", ДатаСвертки);
Запрос.УстановитьПараметр("ПериодЗаписи", НачалоДня(ДатаСвертки + 60*60*24));
Разберем параметры запроса. Если дата свертки установлена, например, на 01.07.2016 23:59:59, то параметр &ПериодЗаписи принимает значение 02.07.2016 00:00:00 (начало первого дня нового периода ведения учета).
Выясним причину использования соединения со СрезомПервых. На первый взгляд кажется, что достаточно просто взять актуальный срез последних на момент свертки и записать его в базу на начало следующего дня. Однако возникают две принципиальные проблемы: бизнес-логика и техническая уникальность ключа записи.
02.07.2016 00:00:00 рабочим документом нового периода уже установлена новая цена или другой показатель, переносить старое значение на эту же дату бессмысленно — оно будет мгновенно перекрыто новой записью.Период. Если периодичность регистра сведений зафиксирована (например, В пределах секунды, В пределах дня, В пределах месяца), платформа не позволяет иметь две записи с одинаковыми измерениями в рамках одного периода. При попытке записать сформированные остатки на 02.07.2016 00:00:00, если на эту дату уже существует запись от документа первого дня нового периода, возникнет ошибка СУБД о неуникальности записей.Обратим внимание на условие проверки свойств регистра:
Если (НЕ ТекРег.ПериодичностьРегистраСведений = Метаданные.СвойстваОбъектов.ПериодичностьРегистраСведений.ПозицияРегистратора)
Рассмотрим различие двух вариантов настройки периодичности регистров сведений, подчиненных регистратору:
02.07.2016 00:00:00 в базе может существовать несколько записей с одинаковым набором измерений, сделанных разными документами. Ошибки уникальности не возникнет, поэтому для таких регистров выбираются все записи среза последних без дополнительных фильтров.ТабРегСрезПервых.Период НЕ ЕСТЬ NULL), начальный остаток по данным измерениям не формируется.При самостоятельной разработке алгоритмов свертки или переноса срезов сведений следует придерживаться следующих правил:
1. Фиксация входящих остатков на конец дня: Чтобы избежать совпадения времени сверточных записей и новых первичных документов, документы ввода остатков чаще всего записывают на время 23:59:59 дня, предшествующего началу нового периода (например, 01.07.2016 23:59:59).
2. Учет структуры ключа записи: Перед выполнением групповой записи через наборы записей с установленным свойством ОбменДанных.Загрузка = Истина всегда проверяйте режим записи и периодичность регистра. Свойство Загрузка = Истина не отменяет физический контроль уникальности ключа на уровне СУБД.