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