Как исправить ошибку «Неверные параметры "*"» в запросе 1С при расчете веса и объема?

Программист 1С v8.3 (Обычные формы) Управленческий учет Торговля и дистрибуция
← На главную

В процессе разработки сложных отчетов или доработки существующих механизмов в 1С программисты часто сталкиваются с необходимостью вычисления производных величин прямо в тексте запроса. Одной из самых распространенных задач является расчет общего веса или объема товара путем умножения количества на соответствующее свойство (вес брутто, высота, ширина). Однако попытка простого умножения часто приводит к ошибке «Неверные параметры "*"». В этой статье мы подробно разберем, почему возникает эта проблема и как правильно составить запрос для корректного расчета характеристик объектов.

Почему возникает ошибка при умножении в запросе?

Разберем первопричину. В типовых конфигурациях 1С (особенно тех, что используют обычные формы, таких как УПП 1.3 или УТ 10.3) значения дополнительных свойств хранятся в регистре сведений ЗначенияСвойствОбъектов. Поле Значение в этом регистре имеет составной тип данных. Оно может содержать число, строку, дату, булево или ссылку на другой объект (например, на справочник ЗначенияСвойствОбъектов).

Проанализируем ситуацию с точки зрения системы: когда мы пишем в запросе ЗначенияСвойствОбъектов.Значение * РасходнаяНакладнаяСостав.Количество, платформа не может гарантировать, что в поле Значение всегда будет находиться число. Язык запросов 1С строго типизирован, и выполнение арифметических операций над полями составного типа запрещено. Именно поэтому возникает ошибка «Неверные параметры "*"» — система сообщает, что один из операндов не является числом.

Решение проблемы через приведение типов

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

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


ВЫРАЗИТЬ(ЗначенияСвойствОбъектов.Значение КАК ЧИСЛО(15, 5)) * РасходнаяНакладнаяСостав.Количество

Здесь мы указываем системе, что данные из регистра нужно воспринимать как число с общей длиной 15 знаков и 5 знаками после запятой. Важно подбирать точность в соответствии с тем, как данные хранятся в вашей базе, чтобы избежать потери данных при округлении.

Правильная обработка пустых значений (NULL)

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

Выясним причину, почему простая конструкция ЕСТЬNULL иногда не спасает. Если мы сначала используем ЕСТЬNULL(Поле, 0), а затем пытаемся умножить, ошибка типа никуда не денется. Правильный порядок действий в цепочке функций должен быть таким:

  1. Сначала проверяем на NULL и заменяем на ноль.
  2. Затем применяем ВЫРАЗИТЬ, чтобы зафиксировать числовой тип.
  3. Только потом выполняем умножение.

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


СУММА(ВЫРАЗИТЬ(ЕСТЬNULL(ЗначенияСвойствБрутто.Значение, 0) КАК ЧИСЛО(15, 5)) * РасходнаяНакладнаяСостав.Количество) КАК ВесБрутто

Расчет объема: работа с несколькими свойствами

Если задача усложняется и нам нужно рассчитать объем (Длина * Ширина * Высота * Количество), количество соединений с регистром свойств растет. Проанализируем пример итогового запроса, который позволяет собрать все данные воедино. В данном случае мы используем несколько левых соединений к одной и той же таблице регистра, но с разными условиями по свойству.


ВЫБРАТЬ
    ДД_МаршрутныйЛистСостав.Ссылка КАК Ссылка,
    СУММА(ВЫРАЗИТЬ(ЕСТЬNULL(ЗначенияСвойствБрутто.Значение, 0) КАК ЧИСЛО(15, 5)) * РасходнаяНакладнаяСостав.Количество) КАК Брутто,
    СУММА(
        ВЫРАЗИТЬ(ЕСТЬNULL(ЗначенияСвойствВысота.Значение, 0) КАК ЧИСЛО(15, 5)) * 
        ВЫРАЗИТЬ(ЕСТЬNULL(ЗначенияСвойствШирина.Значение, 0) КАК ЧИСЛО(15, 5)) * 
        ВЫРАЗИТЬ(ЕСТЬNULL(ЗначенияСвойствДлина.Значение, 0) КАК ЧИСЛО(15, 5)) * 
        РасходнаяНакладнаяСостав.Количество
    ) КАК Объем
ИЗ
    Документ.ДД_МаршрутныйЛист.Состав КАК ДД_МаршрутныйЛистСостав
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.РасходнаяНакладная.Состав КАК РасходнаяНакладнаяСостав 
    ПО ДД_МаршрутныйЛистСостав.Реализация = РасходнаяНакладнаяСостав.Ссылка
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствБрутто 
    ПО (РасходнаяНакладнаяСостав.ЕдиницаИзмерения = ЗначенияСвойствБрутто.Объект) 
    И (ЗначенияСвойствБрутто.Свойство = &СвойствоБрутто)
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствВысота 
    ПО (РасходнаяНакладнаяСостав.ЕдиницаИзмерения = ЗначенияСвойствВысота.Объект) 
    И (ЗначенияСвойствВысота.Свойство = &СвойствоВысота)
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствШирина 
    ПО (РасходнаяНакладнаяСостав.ЕдиницаИзмерения = ЗначенияСвойствШирина.Объект) 
    И (ЗначенияСвойствШирина.Свойство = &СвойствоШирина)
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствДлина 
    ПО (РасходнаяНакладнаяСостав.ЕдиницаИзмерения = ЗначенияСвойствДлина.Объект) 
    И (ЗначенияСвойствДлина.Свойство = &СвойствоДлина)
ГДЕ
    ДД_МаршрутныйЛистСостав.Ссылка.Проведен = ИСТИНА
СГРУППИРОВАТЬ ПО
    ДД_МаршрутныйЛистСостав.Ссылка

Оптимизация: Метод «Свертки» вместо множественных соединений

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

Мы можем соединиться с регистром только один раз, а затем использовать агрегатную функцию МАКСИМУМ с условием ВЫБОР КОГДА. Это позволит СУБД просканировать таблицу свойств гораздо быстрее.

Пример оптимизированного расчета:


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

Почему результат запроса может быть пустым?

Если код написан верно, но вес или объем все равно возвращаются нулевыми, проанализируем настройки метаданных. В 1С свойства могут быть привязаны к разным объектам:

В приведенных выше примерах соединение идет по полю ЕдиницаИзмерения. Если в вашей базе вес заполнен в карточке номенклатуры, а не для каждой единицы измерения отдельно, то условие связи РасходнаяНакладнаяСостав.ЕдиницаИзмерения = ЗначенияСвойств.Объект не сработает. В таком случае необходимо изменить объект связи на Номенклатура.

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

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

Соблюдение этих правил позволит вам создавать надежные и быстрые запросы для расчета любых физических показателей товаров, как это реализовано в инструменте Подробный отчет по номенклатуре, написанный в СКД.

← На главную