При переносе данных или выполнении сложных запросов в среде 1С:Предприятие, работающей совместно с Microsoft SQL Server, программисты часто сталкиваются с пугающей ошибкой: Добавление значения в столбец "datetime" привело к переполнению. Эта ситуация особенно характерна для работы со старыми конфигурациями, такими как ЗУП 2.5, при попытке миграции на новые платформы. Проблема кроется в фундаментальном различии механизмов хранения дат в 1С и СУБД. В этой статье мы подробно разберем, почему возникает эта ошибка, и рассмотрим все доступные способы её решения.
Для начала проанализируем ситуацию. В системе 1С минимально возможная дата — это 01.01.0001 00:00:00 (так называемая "пустая дата"). Однако Microsoft SQL Server при использовании стандартного типа данных datetime поддерживает диапазон дат только от 1 января 1753 года до 31 декабря 9999 года.
Чтобы "подружить" эти две системы, платформа 1С при записи пустой даты в таблицу SQL преобразует её в соответствии с параметром Смещение дат, который задается при создании базы данных:
01.01.0001 превращается в 01.01.1753 в SQL.01.01.0001 превращается в 01.01.2001 в SQL.Ошибка возникает в тот момент, когда в запросе используется функция ДОБАВИТЬКДАТЕ с отрицательным числом (вычитание). Рассмотрим конкретный пример из кода: ДОБАВИТЬКДАТЕ(РаботникиОрганизацииСрезПоследних.ПериодЗавершения, ДЕНЬ, -1). Если в поле ПериодЗавершения содержится пустая дата, а в базе установлено смещение 0, то SQL Server пытается выполнить операцию 1753-01-01 минус 1 день. Результатом должна стать дата 31.12.1752, которая выходит за границы допустимого диапазона datetime. В итоге СУБД возвращает ошибку переполнения, и выполнение кода прерывается.
Интересно заметить, что конструкция ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), ДЕНЬ, -1) может отрабатывать без ошибок. Давайте разберемся, почему так происходит. Когда платформа 1С видит в запросе константу (литерал), она старается вычислить значение еще на этапе подготовки запроса. Если же в функцию передается поле таблицы, 1С транслирует это в SQL-функцию DATEADD. Вычисление происходит непосредственно на стороне сервера базы данных, который и "спотыкается" о невозможность получения даты ранее 1753 года. Отследить проблемный код и оценить нагрузку поможет анализ SQL сервера глазами 1С-ника.
Самый надежный способ решить проблему "в лодке" — это модификация текста запроса. Нам нужно исключить попытку арифметических действий над датой, если она является пустой. Для этого воспользуемся конструкцией ВЫБОР КОГДА ТОГДА.
Рассмотрим пример правильного написания запроса:
ВЫБРАТЬ
ВЫБОР
КОГДА РаботникиОрганизацииСрезПоследних.ПериодЗавершения = ДАТАВРЕМЯ(1, 1, 1)
ТОГДА ДАТАВРЕМЯ(1, 1, 1)
ИНАЧЕ ДОБАВИТЬКДАТЕ(РаботникиОрганизацииСрезПоследних.ПериодЗавершения, ДЕНЬ, -1)
КОНЕЦ КАК ПериодПредварительный
ИЗ
РегистрСведений.РаботникиОрганизации.СрезПоследних(&Период, ) КАК РаботникиОрганизацииСрезПоследних
В данном случае, если ПериодЗавершения пуст, функция ДОБАВИТЬКДАТЕ не будет вызываться на уровне SQL, и мы получим корректный результат без переполнения.
Если вы столкнулись с этой ошибкой во время разовой операции (например, при переносе данных из ЗУП 2.5 в ЗУП 3.1), и у вас нет возможности или желания править типовой код общего модуля ПроцедурыПерсонифицированногоУчетаПолныеПрава, мы можем пойти по пути наименьшего сопротивления.
Файловая СУБД 1С (собственный движок платформы) не имеет ограничений, присущих MS SQL Server. Она корректно обрабатывает даты вплоть до 0001 года. Алгоритм действий будет следующим:
.dt..dt в файловую базу.Это гарантированно избавит вас от ошибок HRESULT=80040E07 на этапе выполнения запросов к кадровым данным.
Если проблема возникает регулярно в рабочей базе, проанализируем настройки подключения к SQL-серверу. Проблема со смещением 0 часто встречается в базах, которые были созданы очень давно. Современным стандартом для 1С является Смещение 2000.
Важно: Вы не можете просто изменить этот параметр в существующей базе через консоль SQL. Чтобы изменить смещение, необходимо:
.dt)..dt обратно.Теперь пустая дата в SQL будет представлена как 01.01.2001. При вычитании одного дня получится 31.12.2000, что находится далеко от критической границы 1753 года, и запросы будут отрабатывать корректно. После завершения всех процедур не забудьте про настройку регламентных операций MS SQL Server и оптимизацию индексов по современным методикам, чтобы обеспечить стабильную работу новой базы.
Иногда полезно проанализировать, почему в поле ПериодЗавершения вообще оказываются пустые значения там, где логика кода их не ждет. Это не единственная аномалия с датами, с которой можно столкнуться: например, известна необходимость исправления ошибки записи данных на дату "31.12.1899". Проанализируем ситуацию в регистре сведений РаботникиОрганизации. Если бизнес-логика позволяет, можно написать простую обработку, которая заполнит пустые значения дат "заглушками" (например, очень большой датой — 31.12.3999).
Пример кода для исправления данных:
Выборка = РегистрыСведений.РаботникиОрганизации.Выбрать();
Пока Выборка.Следующий() Цикл
Если Выборка.ПериодЗавершения = '00010101' Тогда
МенеджерЗаписи = РегистрыСведений.РаботникиОрганизации.СоздатьМенеджерЗаписи();
ЗаполнитьЗначенияСвойств(МенеджерЗаписи, Выборка);
МенеджерЗаписи.ПериодЗавершения = Дата(3999, 12, 31);
МенеджерЗаписи.Записать(Истина);
КонецЕсли;
КонецЦикла;
Однако будьте осторожны: такое изменение может повлиять на логику отчетов и алгоритмы расчета зарплаты, поэтому этот метод стоит использовать только в крайнем случае или для временных целей переноса.
Мы проанализировали специфическую ошибку SQL Server при работе с датами в 1С. Основная причина — попытка выйти за пределы 1753 года при операциях над пустыми датами со смещением 0. Для исправления ситуации мы рекомендуем:
ВЫБОР КОГДА для проверки на ДАТАВРЕМЯ(1, 1, 1).Помните, что использование datetime2 в новых версиях SQL Server могло бы решить эту проблему на корню, но платформа 1С продолжает использовать классический datetime для обеспечения широкой совместимости. Поэтому знание механизмов смещения и грамотная настройка регламентных операций MS SQL Server остаются критически важными для администратора и программиста 1С.