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

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

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

Неверные параметры "*"

Разберем подробную причину возникновения этой ошибки при обращении к дополнительным реквизитам объектов и рассмотрим правильные способы приведения типов данных в языке запросов платформы 1С:Предприятие.

Анализируем исходную ситуацию и причину ошибки

Посмотрим на пример выражения в запросе, которое вызывало ошибку:


ВЫБОР 
    КОГДА ВТ.ЕдиницаХранения = &ЕдиницаХранения ТОГДА ВТ.Количество
    ИНАЧЕ ВЫБОР 
              КОГДА ВТ.ВесШтуки = 0 ТОГДА ВТ.ВесПогонногоМетра * ВТ.Количество / 1000
              ИНАЧЕ ВТ.ВесШтуки * ВТ.Количество / 1000
    КОНЕЦ     
КОНЕЦ

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

Выясним истинную причину такого поведения платформы 1С:

  1. Составной тип данных: Реквизит Значение табличной части ДополнительныеРеквизиты справочников (или планов видов характеристик) имеет составной тип: Число, Строка, Дата, Булево, а также ссылки на различные справочники. Язык запросов 1С запрещает использование арифметических операторов (*, /, +, -) с полями составного типа, даже если в конкретной строке фактически записано числовое значение.
  2. Особенность функции ЕСТЬNULL: Конструкция ЕСТЬNULL(Поле, 0) подменяет значение NULL на ноль, но не изменяет и не сужает тип самого поля в метаданных запроса. Поле для СУБД и транслятора запроса 1С по-прежнему остается составным типом, что и провоцирует ошибку неверных параметров.

Пошаговое решение: явное приведение типов с помощью ВЫРАЗИТЬ

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

Для приведения составного типа к строго определенному примитивному типу в языке запросов 1С предназначена функция ВЫРАЗИТЬ. Чтобы исключить ошибки при отсутствии значений (когда соединение возвращает NULL), объединим ВЫРАЗИТЬ и ЕСТЬNULL в правильном порядке.

  1. Исправляем выборку дополнительных реквизитов во временной таблице

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

    
    ЕСТЬNULL(ВЫРАЗИТЬ(ВесШтуки.С_ВесШтуки КАК ЧИСЛО(15, 3)), 0) КАК ВесШтуки,
    ЕСТЬNULL(ВЫРАЗИТЬ(ВесПогонногоМетра.С_ВесПогонногоМетра КАК ЧИСЛО(15, 3)), 0) КАК ВесПогонногоМетра
    

    Или непосредственно во вложенных запросах выборки реквизитов:

    
    ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
        ВесШтуки.Ссылка КАК Ссылка,
        ВЫРАЗИТЬ(ВесШтуки.Значение КАК ЧИСЛО(15, 3)) КАК С_ВесШтуки
    ИЗ
        Справочник.ХарактеристикиНоменклатуры.ДополнительныеРеквизиты КАК ВесШтуки
    ГДЕ
        ВесШтуки.Свойство = &Свойство) КАК ВесШтуки
    ПО Таблица.Характеристика = ВесШтуки.Ссылка
    
  2. Оптимизируем условное выражение ВЫБОР

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

    
    ВЫБОР 
        КОГДА ВТ.ЕдиницаХранения = &ЕдиницаХранения 
            ТОГДА ВТ.Количество
        КОГДА ВТ.ВесШтуки = 0 
            ТОГДА ВТ.ВесПогонногоМетра * ВТ.Количество / 1000
        ИНАЧЕ ВТ.ВесШтуки * ВТ.Количество / 1000
    КОНЕЦ КАК КоличествоВВесе
    

Важные нюансы и рекомендации при работе с дополнительными реквизитами

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

  1. Порядок вложенности ЕСТЬNULL и ВЫРАЗИТЬ: Всегда размещайте ВЫРАЗИТЬ внутри ЕСТЬNULL. Если применить ВЫРАЗИТЬ(ЕСТЬNULL(Поле, 0) КАК ЧИСЛО), на уровне некоторых СУБД могут возникнуть ошибки несоответствия типов. Правильный шаблон: ЕСТЬNULL(ВЫРАЗИТЬ(Поле КАК ЧИСЛО(15, 2)), 0).
  2. Тип свойства в режиме предприятия: Убедитесь, что в плане видов характеристик или настройках дополнительных реквизитов для данного свойства выбран тип «Число». Если свойство ссылается на справочник ЗначенияСвойствОбъектов, оператор ВЫРАЗИТЬ(... КАК ЧИСЛО) вернет NULL, так как в поле хранится ссылка, а не число.
  3. Защита от дублирования строк: Так как в табличной части может оказаться несколько строк с одинаковым свойством (например, при некорректном программном заполнении), во вложенных запросах к табличным частям рекомендуется использовать группировку МАКСИМУМ(Значение) по ссылке владельца.
← На главную