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

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

При проектировании архитектуры данных в платформе 1С разработчики нередко сталкиваются с необходимостью зафиксировать «стартовое» или «сингулярное» состояние объекта, которое существовало всегда, до начала ведения оперативного учета. Логичным решением кажется использование периодического регистра сведений, где для самой первой записи период оставляют пустым (значение '00010101000000'). Однако при попытке записать такой набор данных платформа бескомпромиссно возвращает ошибку: «Период не может быть пустым!».

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

Технический способ записи пустой даты в период

Платформа 1С выполняет жесткую проверку заполнения периода при записи набора записей периодического регистра. Отключить эту проверку через свойство «Проверка заполнения» в конфигураторе невозможно, так как это свойство регулирует только валидацию поля ввода на форме, но не защищает на уровне СУБД. Тем не менее, лазейка существует.

Для обхода стандартных платформенных проверок бизнес-логики используется свойство объекта записи ОбменДанными.Загрузка. Установка этого свойства в значение Истина сообщает платформе, что данные записываются в режиме импорта (например, при обмене данными из другой информационной базы), и большинство стандартных проверок и обработчиков событий при этом отключаются.

Рассмотрим пример кода, с помощью которого можно принудительно записать пустую дату в периодический регистр сведений:


НаборЗаписей = РегистрыСведений.ИсторияСтатусов.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Объект.Установить(СсылкаНаОбъект);

НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.Объект = СсылкаНаОбъект;
НоваяЗапись.Период = '00010101000000'; // Пустая дата в 1С
НоваяЗапись.Статус = Справочники.СтатусыОбъектов.Исходный;

// Включаем режим загрузки для обхода проверки незаполненного периода
НаборЗаписей.ОбменДанными.Загрузка = Истина;

Попытка
    НаборЗаписей.Записать();
    Сообщить("Запись с пустым периодом успешно сохранена в базу данных!");
Исключение
    Сообщить("Ошибка при записи: " + ОписаниеОшибки());
КонецПопытки;

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

Почему период не должен быть пустым: особенности СУБД

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

Разберем специфику хранения пустых дат в различных СУБД:

  1. Microsoft SQL Server. Стандартный тип данных DATETIME в MS SQL не поддерживает даты ранее 01.01.1753. Чтобы обойти это ограничение и позволить пользователям 1С использовать пустые даты (которые в 1С соответствуют 01.01.0001), платформа использует механизм смещения дат. При создании базы данных по умолчанию задается смещение на 2000 лет. Таким образом, пустая дата 01.01.0001 хранится в таблицах MS SQL как 01.01.2001. Использование такой даты в индексах ключевых полей может вызывать проблемы с селективностью и фрагментацией индексов, поскольку СУБД не может оптимизировать запросы по «фиктивно нулевым» ключевым значениям.
  2. PostgreSQL. Данная СУБД нативно поддерживает даты начиная с 0001-01-01. Однако драйверы 1С обеспечивают унификацию поведения для всех поддерживаемых СУБД, из-за чего особенности работы с индексами остаются одинаковыми во избежание платформенных коллизий при миграции баз данных.

Скрытые риски использования пустой даты в периоде

Запись пустой даты через ОбменДанными.Загрузка = Истина — это мина замедленного действия. Ниже приведены основные проблемы, с которыми вы гарантированно столкнетесь в процессе эксплуатации информационной базы.

1. Тестирование и исправление информационной базы (ТИИ)

Стандартный инструмент администратора 1С «Тестирование и исправление» при запуске проверки логической целостности базы данных анализирует структуру таблиц. Обнаружив в периодическом регистре сведений запись с пустым периодом, утилита расценит это как критическую ошибку структуры данных (нарушение логики работы платформы с периодическими регистрами). В зависимости от выбранных настроек ТИИ, эти записи будут либо безвозвратно удалены, либо период в них будет принудительно заменен на минимально возможную корректную дату СУБД, что полностью разрушит исходную логику вашей конфигурации.

2. Рассинхронизация при обменах данными

Когда вы записываете набор записей с установленным флагом ОбменДанными.Загрузка = Истина, платформа по умолчанию отключает авторегистрацию изменений на узлах планов обмена. Это означает, что созданная запись с пустым периодом не будет зарегистрирована для отправки в другие узлы распределенной информационной базы (РИБ) или внешние системы. Данные в базах-приемниках начнут расходиться, что потребует ручного вмешательства и принудительной перерегистрации изменений.

3. Некорректная работа виртуальных таблиц и физических итогов

Начиная с версии платформы 8.3, для периодических регистров сведений была добавлена оптимизация — использование физических таблиц итогов для срезов (свойства «Разрешить итоги: Срез последних» и «Разрешить итоги: Срез первых»). СУБД больше не рассчитывает срезы динамически на лету при каждом запросе, а хранит рассчитанные данные в отдельной служебной таблице базы данных.

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

Рекомендуемые альтернативы (Best Practices)

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

Вариант 1. Использование условно-минимальной технической даты

Вместо пустой даты 01.01.0001 запишем предопределенную минимальную дату, которая гарантированно будет меньше любой даты оперативного учета, но при этом будет являться валидной для платформы 1С. В типовых конфигурациях (например, 1С:ERP, 1С:КА, 1С:УТ) для этих целей традиционно используется дата начала прошлого века — 01.01.1900 (или в ряде случаев 02.01.0001).

Преимущества данного подхода:

Пример записи с условно-минимальной технической датой:


НаборЗаписей = РегистрыСведений.ИсторияСтатусов.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Объект.Установить(СсылкаНаОбъект);

НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.Объект = СсылкаНаОбъект;
// Записываем безопасную минимальную дату вместо пустой
НоваяЗапись.Period = '19000101000000'; 
НоваяЗапись.Статус = Справочники.СтатусыОбъектов.Исходный;

НаборЗаписей.Записать(); // Запись выполняется в обычном режиме без флага Загрузка

Вариант 2. Переход на непериодический регистр с измерением «Дата»

Если бизнес-логика вашей задачи категорически требует наличия незаполненной даты и вы не хотите использовать «фейковые» значения вроде 01.01.1900, наиболее правильным решением будет отказ от периодичности регистра.

Мы создаем **непериодический** регистр сведений, добавляем в него явное измерение Дата с типом Дата и в свойствах этого измерения снимаем флаг «Проверка заполнения». Теперь дата может быть абсолютно пустой.

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


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

РезультатЗапроса = Запрос.Выполнить();

Проанализируем этот запрос по шагам. В первом пакете мы выбираем из непериодического регистра сведений максимальную дату для каждого объекта и помещаем результат во временную таблицу ВТ_ПоследниеДаты. Пустые даты при группировке по максимуму будут считаться самыми ранними (минимальными) значениями, поэтому если у объекта есть более поздние записи с заполненной датой, они успешно перекроют пустую дату.

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

Резюме

Мы выяснили причину поведения платформы при работе с пустыми датами в периодических регистрах сведений и разобрали технический обход ограничений через ОбменДанными.Загрузка = Истина. Помните, что данный обход несет колоссальные риски для стабильности базы данных (ошибки при тестировании и исправлении, сбои в расчете физических итогов срезов последних, проблемы синхронизации в РИБ).

В реальной практике разработки всегда отдавайте предпочтение безопасным альтернативам: используйте условно-минимальную техническую дату (например, 01.01.1900) или переводите регистр в статус непериодического с ручным расчетом среза последних через запросы. Это убережет ваши данные от разрушения и обеспечит высокую скорость и стабильность работы системы на любых объемах данных.

← На главную