Как исправить ошибку «Преобразование значения к типу Число не может быть выполнено» в 1С

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

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

Выясняем причину ошибки

Проанализируем ситуацию, представленную в коде автора. В примере выполняется вычитание значений в строке таблицы: стрТЗОб.КоличествоРез = стрТЗОб.КоличествоОстаток - стрТЗОб.КоличествоОборот;. Ошибка возникает из-за того, что в одной из переменных вместо ожидаемого числа находится значение NULL.

Важно понимать разницу между нулем и NULL. В системе 1С NULL — это отсутствие значения. Оно часто появляется в результатах запросов, когда используется ЛЕВОЕ СОЕДИНЕНИЕ, и для записи в одной таблице не нашлось соответствующей записи в другой. Математические операции с NULL невозможны: программа не знает, как вычесть «ничто» из числа, поэтому выбрасывает исключение.

Решение №1: Использование функции ЕСТЬNULL в запросе

Самый правильный и эффективный способ избежать этой ошибки — обработать данные еще на этапе выполнения запроса. Если мы ожидаем, что в числовом поле может оказаться пустота, мы должны заменить ее на 0. Для этого в языке запросов 1С существует функция ЕСТЬNULL.

Рассмотрим пример правильного написания части запроса:


ВЫБРАТЬ
    Остатки.Номенклатура КАК Номенклатура,
    ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК КоличествоОстаток,
    ЕСТЬNULL(Обороты.КоличествоОборот, 0) КАК КоличествоОборот
ИЗ
    РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Обороты КАК Обороты
    ПО Остатки.Номенклатура = Обороты.Номенклатура

В этом случае, даже если по конкретной номенклатуре не было оборотов, в таблицу значений попадет число 0, а не NULL. Это позволит выполнять любые математические действия в коде без риска падения системы.

Решение №2: Проверка на NULL непосредственно в коде

Если по каким-то причинам вы не можете изменить текст запроса, ситуацию необходимо обрабатывать при обходе таблицы значений в цикле. Мы можем использовать встроенную функцию ЗначениеЗаполнено() или прямое сравнение с типом NULL.

Проанализируем исправленный вариант цикла:


Для Каждого стрТЗОб Из ТЗОб Цикл
    // Проверяем каждое слагаемое перед расчетом
    ТекОстаток = ?(стрТЗОб.КоличествоОстаток = NULL, 0, стрТЗОб.КоличествоОстаток);
    ТекОборот  = ?(стрТЗОб.КоличествоОборот  = NULL, 0, стрТЗОб.КоличествоОборот);
    
    // Теперь расчет безопасен
    стрТЗОб.КоличествоРез = ТекОстаток - ТекОборот;
КонецЦикла;

Здесь мы использовали тернарный оператор ?(), который проверяет значение на NULL и подставляет 0 в случае необходимости.

Особенности метода «Свернуть» при работе с NULL

Разберем важный нюанс работы метода Свернуть(), который использовался в исходном вопросе. Когда вы вызываете ТЗОб.Свернуть("Номенклатура", "КоличествоОборот..."), система суммирует значения в колонках ресурсов.

Как работает свертка с NULL:

  1. Если в группе строк есть и числа, и NULL, то 1С проигнорирует NULL и вернет сумму чисел.
  2. Если во всех строках данной группы в колонке стоит NULL, то и результатом свертки для этой группы будет NULL.

Именно поэтому ошибка может проявиться «внезапно» на определенных данных, где обороты по товару отсутствуют вовсе.

Оптимизация производительности: Индексация

В коде автора используется метод ТЗОст.Найти(стрТЗОб.Номенклатура, "Номенклатура") внутри цикла. Если в таблицах тысячи строк, такая операция будет работать крайне медленно, так как при каждом поиске система «просматривает» таблицу ТЗОст с самого начала.

Посмотрим, как можно ускорить этот процесс с помощью индексации:


// Перед началом цикла обязательно добавляем индекс
ТЗОст.Индексы.Добавить("Номенклатура");

Для Каждого стрТЗОб Из ТЗОб Цикл
    стрТЗОб.КоличествоОстаток = 0;
    
    // Теперь поиск по индексу работает мгновенно
    стрТЗОст = ТЗОст.Найти(стрТЗОб.Номенклатура, "Номенклатура");
    Если стрТЗОст <> Неопределено Тогда
        стрТЗОб.КоличествоОстаток = стрТЗОст.КоличествоОстаток;
    КонецЕсли;
    
    // Проверка на NULL обязательна, если данные не обработаны в запросе
    стрТЗОб.КоличествоРез = стрТЗОб.КоличествоОстаток - ?(стрТЗОб.КоличествоОборот = NULL, 0, стрТЗОб.КоличествоОборот);
КонецЦикла;

Типизация колонок при создании таблицы

Еще один важный момент — правильное создание колонок. Автор добавляет колонки следующим образом: ТЗОб.Колонки.Добавить("КоличествоРез", Новый ОписаниеТипов("Число")).

Когда вы явно указываете тип Число, система ожидает, что в эту колонку будут записываться только числа. Если результат выражения Число - NULL дает NULL (в некоторых контекстах), попытка записать это значение в типизированную колонку вызовет ошибку. Поэтому всегда инициализируйте значения по умолчанию (например, 0) сразу после создания строки или колонки.

Рекомендации для предотвращения ошибок типа Число

Подводя итог, выделим основные правила безопасной работы с числами в 1С:

  1. Всегда используйте ЕСТЬNULL(Поле, 0) в запросах для всех числовых полей, которые участвуют в соединениях.
  2. Проверяйте результат поиска: метод Найти() возвращает Неопределено, если строка не найдена. Попытка обратиться к свойству через точку (стрТЗОст.Количество) в этом случае вызовет другую ошибку.
  3. Используйте индексацию: если вы ищете данные в одной таблице на основании данных другой в цикле, индекс по полю поиска обязателен для производительности.
  4. Контролируйте типы: если вы программно создаете таблицу значений, старайтесь задавать квалификаторы числа (точность и разрядность), чтобы избежать проблем с округлением.

Применяя эти методы, вы не только избавитесь от ошибки преобразования типа, но и сделаете свой код более надежным и быстрым.

← На главную