При разработке и доработке отчетов в 1С разработчики часто сталкиваются с ситуацией, когда попытка выполнить простую арифметическую операцию (умножение, деление, сложение или вычитание) в тексте запроса приводит к ошибке синтаксического анализатора:
Неверные параметры "*"
Разберем подробную причину возникновения этой ошибки при обращении к дополнительным реквизитам объектов и рассмотрим правильные способы приведения типов данных в языке запросов платформы 1С:Предприятие.
Посмотрим на пример выражения в запросе, которое вызывало ошибку:
ВЫБОР
КОГДА ВТ.ЕдиницаХранения = &ЕдиницаХранения ТОГДА ВТ.Количество
ИНАЧЕ ВЫБОР
КОГДА ВТ.ВесШтуки = 0 ТОГДА ВТ.ВесПогонногоМетра * ВТ.Количество / 1000
ИНАЧЕ ВТ.ВесШтуки * ВТ.Количество / 1000
КОНЕЦ
КОНЕЦ
На первый взгляд, все поля являются числами: количество получено из регистра накопления, а вес получен из табличной части дополнительных реквизитов и обернут в ЕСТЬNULL(..., 0). Однако платформа выдает ошибку на строке с умножением.
Выясним истинную причину такого поведения платформы 1С:
Значение табличной части ДополнительныеРеквизиты справочников (или планов видов характеристик) имеет составной тип: Число, Строка, Дата, Булево, а также ссылки на различные справочники. Язык запросов 1С запрещает использование арифметических операторов (*, /, +, -) с полями составного типа, даже если в конкретной строке фактически записано числовое значение.ЕСТЬNULL: Конструкция ЕСТЬNULL(Поле, 0) подменяет значение NULL на ноль, но не изменяет и не сужает тип самого поля в метаданных запроса. Поле для СУБД и транслятора запроса 1С по-прежнему остается составным типом, что и провоцирует ошибку неверных параметров.Разберем по шагам, как правильно преобразовать тип поля к числовому, чтобы платформа разрешила выполнение арифметических операций.
Для приведения составного типа к строго определенному примитивному типу в языке запросов 1С предназначена функция ВЫРАЗИТЬ. Чтобы исключить ошибки при отсутствии значений (когда соединение возвращает NULL), объединим ВЫРАЗИТЬ и ЕСТЬNULL в правильном порядке.
Исправляем выборку дополнительных реквизитов во временной таблице
В секции соединения с табличной частью дополнительных реквизитов оборачиваем реквизит Значение в конструкцию ВЫРАЗИТЬ(... КАК ЧИСЛО(...)), после чего обрабатываем возможное значение NULL:
ЕСТЬNULL(ВЫРАЗИТЬ(ВесШтуки.С_ВесШтуки КАК ЧИСЛО(15, 3)), 0) КАК ВесШтуки,
ЕСТЬNULL(ВЫРАЗИТЬ(ВесПогонногоМетра.С_ВесПогонногоМетра КАК ЧИСЛО(15, 3)), 0) КАК ВесПогонногоМетра
Или непосредственно во вложенных запросах выборки реквизитов:
ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
ВесШтуки.Ссылка КАК Ссылка,
ВЫРАЗИТЬ(ВесШтуки.Значение КАК ЧИСЛО(15, 3)) КАК С_ВесШтуки
ИЗ
Справочник.ХарактеристикиНоменклатуры.ДополнительныеРеквизиты КАК ВесШтуки
ГДЕ
ВесШтуки.Свойство = &Свойство) КАК ВесШтуки
ПО Таблица.Характеристика = ВесШтуки.Ссылка
Оптимизируем условное выражение ВЫБОР
После того как поля стали строго типизированными числами, мы можем упростить вложенные конструкции ВЫБОР, сделав код более читаемым и производительным:
ВЫБОР
КОГДА ВТ.ЕдиницаХранения = &ЕдиницаХранения
ТОГДА ВТ.Количество
КОГДА ВТ.ВесШтуки = 0
ТОГДА ВТ.ВесПогонногоМетра * ВТ.Количество / 1000
ИНАЧЕ ВТ.ВесШтуки * ВТ.Количество / 1000
КОНЕЦ КАК КоличествоВВесе
Рассмотрим несколько практических моментов, о которых важно помнить при составлении подобных запросов:
ЕСТЬNULL и ВЫРАЗИТЬ: Всегда размещайте ВЫРАЗИТЬ внутри ЕСТЬNULL. Если применить ВЫРАЗИТЬ(ЕСТЬNULL(Поле, 0) КАК ЧИСЛО), на уровне некоторых СУБД могут возникнуть ошибки несоответствия типов. Правильный шаблон: ЕСТЬNULL(ВЫРАЗИТЬ(Поле КАК ЧИСЛО(15, 2)), 0).ЗначенияСвойствОбъектов, оператор ВЫРАЗИТЬ(... КАК ЧИСЛО) вернет NULL, так как в поле хранится ссылка, а не число.МАКСИМУМ(Значение) по ссылке владельца.