Как исправить ошибку арифметического переполнения numeric при отражении документов в регламентированном учете 1С:ERP?

Программист 1С v8.3 (Управляемые формы) 1С:ERP Управление предприятием Бухгалтерский учет Промышленность, строительство и АПК
← На главную

При проведении или отражении документов производства и переработки давальческого сырья (например, документов Этап производства или Отчет давальцу) в регламентированном учете системы 1С:ERP пользователи могут столкнуться с аварийным завершением операции: Microsoft OLE DB Driver for SQL Server: Ошибка арифметического переполнения при преобразовании numeric к типу данных numeric. HRESULT=80040E57, SQLSrvr: SQLSTATE=22003, native=8115. Разберем детально, почему возникает эта ошибка, как работает механизм вычислений в СУБД MS SQL Server и какими способами можно восстановить работоспособность закрытия месяца и отражения документов.

Причины возникновения ошибки на уровне СУБД и платформы

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

Рассмотрим выражение, на котором происходит сбой:


ВЫРАЗИТЬ((Т.Количество / Детализация.Количество) * Детализация.СтоимостьРегл КАК ЧИСЛО(31,2)) КАК СтоимостьРегл

Проанализируем, как MS SQL Server вычисляет такое выражение. При операциях с типом данных numeric СУБД динамически рассчитывает точность (precision) и масштаб (scale) для каждого промежуточного подвыражения:

  1. Промежуточное деление: выражение (Т.Количество / Детализация.Количество) порождает результат с максимальным увеличением разрядности дробной части. Для сохранения точности СУБД отводит под масштаб значительную часть доступной разрядности.
  2. Последующее умножение: при умножении полученного частного на Детализация.СтоимостьРегл суммарная необходимая разрядность превышает лимит MS SQL Server в 38 десятичных знаков. В этой ситуации СУБД принудительно обрезает масштаб, высвобождая место под целую часть.
  3. Переполнение: если реальное число целых знаков не помещается в оставшиеся разряды промежуточного типа, СУБД генерирует исключение native error 8115. Важно отметить, что ошибка происходит в момент расчета математического выражения внутри ядра SQL Server, то есть до того, как сработает внешняя функция приведения типа ВЫРАЗИТЬ(... КАК ЧИСЛО(31,2)) (транслируемая в CAST).

Вторая составляющая проблемы — накопление аномально больших чисел (триллионов и квадриллионов) в регистрах учета. Это происходит в результате сбоя численных методов при решении СЛАУ или циклического списания затрат, когда система пытается распределить ненулевую стоимость на стремящуюся к нулю или микроскопическую количественную базу (например, при наличии остатков порядка 0.00001 в цеховых кладовых).

Способ 1. Изменение порядка математических операций в запросе

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

Вместо предварительного деления выполним сначала умножение стоимостного показателя на количество, а затем деление на базу:


// Исходный вариант, приводящий к переполнению промежуточного типа:
// ВЫРАЗИТЬ((Т.Количество / Детализация.Количество) * Детализация.СтоимостьРегл КАК ЧИСЛО(31,2)) КАК СтоимостьРегл

// Скорректированный вариант:
ВЫРАЗИТЬ(Детализация.СтоимостьРегл / Детализация.Количество * Т.Количество КАК ЧИСЛО(31,2)) КАК СтоимостьРегл,
ВЫРАЗИТЬ(Детализация.НДСРегл / Детализация.Количество * Т.Количество КАК ЧИСЛО(31,2)) КАК НДСРегл,
ВЫРАЗИТЬ(Детализация.СтоимостьУпр / Детализация.Количество * Т.Количество КАК ЧИСЛО(31,2)) КАК СтоимостьУпр,
ВЫРАЗИТЬ(Детализация.НДСУпр / Детализация.Количество * Т.Количество КАК ЧИСЛО(31,2)) КАК НДСУпр,
ВЫРАЗИТЬ(Детализация.ПостояннаяРазница / Детализация.Количество * Т.Количество КАК ЧИСЛО(31,2)) КАК ПостояннаяРазница,
ВЫРАЗИТЬ(Детализация.ВременнаяРазница / Детализация.Количество * Т.Количество КАК ЧИСЛО(31,2)) КАК ВременнаяРазница

Также можно воспользоваться принудительным ограничением разрядности промежуточного коэффициента через функцию ВЫРАЗИТЬ непосредственно внутри скобок, чтобы частное не расширялось до 38 знаков:


ВЫРАЗИТЬ(ВЫРАЗИТЬ(Т.Количество / Детализация.Количество КАК ЧИСЛО(15, 6)) * Детализация.СтоимостьРегл КАК ЧИСЛО(31,2)) КАК СтоимостьРегл

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

Способ 2. Поиск и исправление аномальных данных в регистрах

Разберем по шагам, как локализовать некорректные записи в базе данных, провоцирующие гигантские суммы:

  1. Локализуем проблемную позицию: определим номенклатуру, характеристику и серию, по которым регистрируется сбой отражения. Как правило, ошибка привязана к узкому списку номенклатурных позиций выпуска или материалов.
  2. Проверим регистр сведений ДетализацияСебестоимостиПартийПродукции: напишем проверочный запрос в консоли запросов с отбором по модулю сумм, выходящих за рамки здравого смысла:
    
    ВЫБРАТЬ
        Т.ПериодРегистрации,
        Т.Регистратор,
        Т.Номенклатура,
        Т.Количество,
        Т.СтоимостьРегл,
        Т.СтоимостьУпр
    ИЗ
        РегистрСведений.ДетализацияСебестоимостиПартийПродукции КАК Т
    ГДЕ
        Т.Номенклатура В (&СписокПроблемнойНоменклатуры)
        И (Т.СтоимостьРегл > 100000000000 ИЛИ Т.СтоимостьРегл < -100000000000)
    
  3. Проанализируем движения по цеховым кладовым: проверим остатки по регистру накопления СебестоимостьТоваров. Если в цепочке документов используется передача в цеховую кладовую, а затем списание на выпуск, проверим наличие микроскопических «хвостов» количества (например, остаток 0.00001 при стоимости в несколько сотен тысяч рублей). Наличие таких делений порождает расчетную цену единицы, стремящуюся к бесконечности.
  4. Скорректируем зависшие остатки: если обнаружены некорректные остатки за прошлые закрытые периоды, введем документ КорректировкаРегистров на конец предшествующего месяца, обнулив аномальные стоимостные или количественные хвосты по соответствующим ключам аналитики.

Способ 3. Установка исправлений от разработчика и перезакрытие месяца

Рассмотрим системное решение. Фирма «1С» зафиксировала ошибку в подсистеме расчета себестоимости и распределения затрат по статьям калькуляции при включенном детализированном учете и использовании цеховых кладовых (ошибка зарегистрирована под номером 00-00934588).

Для гарантированного устранения проблемы выполним следующие действия:

  1. Проверим наличие и установим актуальный патч (исправление) для используемого релиза 1С:ERP, закрывающий ошибку алгоритма расчета себестоимости 20-го счета.
  2. Отменим проведение документов распределения расходов и расчета себестоимости за проблемный месяц.
  3. Выполним повторный запуск процедуры ЗакрытиеМесяца.
  4. После перерасчета себестоимости запустим регламентное задание или обработку ОтражениеДокументовВРеглУчете. Аномальные суммы будут списаны корректно, и документы отразятся в учете без системных сбоев.
← На главную