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

Программист 1С v8.3 (Обычные формы) 1С:Зарплата и Управление Персоналом
← На главную

При разработке отчетов или обработок в среде 1С:Предприятие 8 программисты часто сталкиваются с ситуацией, когда стандартная математическая операция (например, умножение) в запросе вызывает ошибку неверные параметры "*". Ситуация выглядит парадоксально: вы проверяете тип значения в консоли запросов, видите там число, но система отказывается выполнять вычисления. Рассмотрим подробно, почему это происходит и как правильно составить запрос, чтобы избежать подобных проблем.

Разбор ситуации: почему "Число" — это не всегда число

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


ВЫБРАТЬ
    ЗначенияСвойствОбъектов.Значение * 2 КАК ИтоговыйКоэффициент
ИЗ
    РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектов

Даже если в конкретной записи хранится значение 0.75, платформа выдаст ошибку. Причина кроется в метаданных. Поле Значение в таких регистрах имеет составной тип данных (например, оно может хранить строку, число, дату или ссылку). Для системы компоновки запросов и SQL-сервера это означает, что тип поля неопределен заранее.

Выясним причину, по которой функция ТИПЗНАЧЕНИЯ может вводить в заблуждение. Когда мы вызываем ТИПЗНАЧЕНИЯ(Коэффициент) в запросе, система анализирует фактическое содержимое конкретной ячейки в уже извлеченной строке. Однако компилятор запроса анализирует структуру таблицы целиком. Поскольку в описании поля значится "составной тип", математические операции запрещены на этапе подготовки запроса, так как система не может гарантировать, что во всех строках окажется число.

Решение проблемы: использование оператора ВЫРАЗИТЬ

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


ВЫБРАТЬ
    ВЫРАЗИТЬ(ЗначенияСвойствОбъектов.Значение КАК ЧИСЛО(15, 3)) * 2 КАК Результат
ИЗ
    РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектов

При использовании этого оператора важно помнить о следующих правилах:

Обработка пустых значений через ЕСТЬNULL

Часто дополнительные свойства выбираются через левое соединение. Если свойство у объекта не задано, в поле попадет NULL. Любая математическая операция с NULL (например, NULL * 2) всегда возвращает NULL, что может привести к неверным итогам в отчете.

Посмотрим на пример правильной комбинации функций для обеспечения отказоустойчивости запроса:


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

Разберем, почему порядок функций важен. В некоторых версиях платформы (особенно 8.2) конструкция ВЫРАЗИТЬ(ЕСТЬNULL(Коэффициент, 0) КАК ЧИСЛО) может вызвать ошибку в конфигураторе, хотя в консоли запросов она будет работать. Наиболее надежным и стандартным способом считается сначала приведение типа через ВЫРАЗИТЬ, а затем замена пустого значения на ноль через ЕСТЬNULL.

Влияние на производительность и специфику СУБД

Проанализируем ситуацию с точки зрения производительности. Использование ВЫРАЗИТЬ в секции ВЫБРАТЬ практически не замедляет работу. Однако, если вы начнете использовать эту конструкцию в секции ГДЕ или в условиях соединения, это может привести к серьезным проблемам:

  1. Индексация: SQL-сервер не сможет использовать индексы по полю "Значение", если оно обернуто в функцию. Это приведет к полному сканированию таблицы (Table Scan).
  2. Типизация в PostgreSQL: Если ваша база работает на PostgreSQL, строгость типов там выше, чем в MS SQL Server. Явное приведение типов в запросах 1С для этой СУБД является критически важным для стабильной работы.

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

Итоговый пример реализации

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


ВЫБРАТЬ
    Продажи.Документ КАК Документ,
    ЕСТЬNULL(ВЫРАЗИТЬ(Свойства.Значение КАК ЧИСЛО(10, 2)), 0) КАК Коэфф
ПОМЕСТИТЬ ВТ_Данные
ИЗ
    РегистрНакопления.Продажи КАК Продажи
ЛЕВОЕ СОЕДИНЕНИЕ 
    РегистрСведений.ЗначенияСвойствОбъектов КАК Свойства
    ПО Продажи.Документ = Свойства.Объект
    И Свойства.Свойство = &СвойствоКоэффициент;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ_Данные.Документ,
    ВТ_Данные.Коэфф * 100 КАК ПроцентныйКоэффициент
ИЗ
    ВТ_Данные КАК ВТ_Данные

Таким образом, мы гарантируем отсутствие ошибок типизации и обеспечиваем корректную обработку пустых значений.

← На главную