Каждый разработчик 1С рано или поздно сталкивается с удивительным и на первый взгляд необъяснимым поведением платформы. Представьте ситуацию: вы пишете простой и интуитивно понятный запрос, в котором перемножаете два числовых поля — например, цену и количество товара. С точки зрения логики и типов данных в метаданных всё настроено абсолютно верно. Более того, этот запрос прекрасно выполняется в режиме «1С:Предприятие», в коде обработок или в Консоли запросов. Но стоит вам попытаться открыть этот запрос в Конструкторе запросов в Конфигураторе, как система тут же выдает ошибку: «Не верные параметры "*"».
В этой статье мы подробно проанализируем, почему возникает эта ошибка, разберем внутренние механизмы работы парсера платформы 1С и рассмотрим пошаговые сценарии решения этой проблемы.
Давайте обратимся к практическому примеру. В запросе разработчик пытается вычислить сумму по строке документа поступления, перемножая поля табличной части:
ВЫБРАТЬ
ПриобретениеТоваровУслугТовары.Количество КАК Количество,
ПриобретениеТоваровУслугТовары.Цена КАК ТАБ_Цена,
ПриобретениеТоваровУслугТовары.Количество * ПриобретениеТоваровУслугТовары.Цена КАК СуммаРегл
ИЗ
Документ.ПриобретениеТоваровУслуг.Товары КАК ПриобретениеТоваровУслугТовары
Оба поля — и Количество, и Цена — имеют строго числовой тип в метаданных конфигурации. Однако Конструктор запросов наотрез отказывается сохранять или редактировать это выражение, ссылаясь на некорректность оператора умножения. При этом попытки обернуть поля в функции ЕСТЬNULL или явно привести их к типу через ВЫРАЗИТЬ не приносят желаемого результата.
Такое поведение объясняется фундаментальным различием между тем, как текст запроса анализируется визуальным Конструктором запросов в Конфигураторе, и тем, как он исполняется непосредственно СУБД на сервере. Выделим несколько ключевых причин этой проблемы и разберем методы их устранения.
Самая частая и неочевидная причина, из-за которой «спотыкается» парсер Конструктора запросов — это наличие в тексте так называемых неразрывных пробелов (символ с ASCII-кодом 160 или NBSP).
Как они попадают в код? Чаще всего это происходит при копировании фрагментов запросов из мессенджеров, писем, веб-страниц форумов или Skype. Внешне такой пробел ничем не отличается от обычного пробела (символ с кодом 32), но для синтаксического анализатора Конструктора запросов они принципиально различны:
Цена [NBSP]*[NBSP] Количество превращается в глазах парсера в единый нечитаемый идентификатор, что и приводит к ошибке «Не верные параметры "*"».Почему же тогда этот запрос без проблем работает в режиме «1С:Предприятие» и Консоли запросов? Дело в том, что перед отправкой запроса на СУБД механизм трансляции SDBL (внутренний язык запросов 1С) производит предварительную санитизацию текста запроса, автоматически заменяя все неразрывные пробелы на стандартные. Конструктор же запросов в Конфигураторе производит жесткий локальный статический анализ «как есть», без предварительной очистки текста.
Как решить проблему с неразрывными пробелами:
ПриобретениеТоваровУслугТовары.Количество*ПриобретениеТоваровУслугТовары.Цена. В таком случае скрытым символам просто негде будет появиться.Если после полной очистки пробелов Конструктор запросов все равно продолжает выдавать ошибку, дело в проверке типов метаданных. Конструктор запросов 1С выполняет строгую проверку типов полей, участвующих в математических операциях.
Если хотя бы одно из полей (например, в измененной или нетиповой конфигурации) имеет составной тип данных, включающий помимо числа ссылку, строку или булево значение, Конструктор превентивно блокирует операцию умножения. Он логично предполагает, что при наличии в базе данных нечислового значения СУБД выдаст критическую ошибку выполнения.
Как решить проблему типизации:
Для обхода этой проблемы необходимо жестко указать Конструктору, что мы гарантированно работаем с числовым типом данных. Обычная функция ЕСТЬNULL(Поле, 0) не всегда решает проблему, так как она лишь заменяет значение NULL на дефолтное, но не меняет исходное описание доступных типов поля. В схожих ситуациях, когда требуется сопоставить разнородные типы, можно использовать методику сравнения строк с представлениями ссылок в запросах.
Мы должны применить оператор ВЫРАЗИТЬ. Рассмотрим правильный пример приведения типов:
ВЫБРАТЬ
ВЫРАЗИТЬ(ПриобретениеТоваровУслугТовары.Количество КАК ЧИСЛО(15, 3))
*
ВЫРАЗИТЬ(ПриобретениеТоваровУслугТовары.Цена КАК ЧИСЛО(15, 2)) КАК СуммаРегл
ИЗ
Документ.ПриобретениеТоваровУслуг.Товары КАК ПриобретениеТоваровУслугТовары
Использование оператора ВЫРАЗИТЬ сообщает Конструктору запросов, что данные поля на этапе выполнения будут приведены к конкретному числовому типу заданной разрядности. После этого синтаксический анализатор Конфигуратора без лишних вопросов пропустит операцию умножения.
Еще один сценарий, при котором возникает подобное поведение — работа с временными таблицами, которые формируются динамически или передаются в запрос в качестве параметров (например, при передаче Таблицы Значений в запрос).
Если вы помещаете данные во временную таблицу и при этом предварительно не типизируете колонки, Конструктор запросов может присвоить им тип ЛюбаяСсылка или оставить тип неопределенным. Попытка перемножить такие колонки в последующих пакетах запроса гарантированно вызовет ошибку «Не верные параметры "*"». Для быстрого обнаружения подобных проблем во временных таблицах и запросах можно использовать инструмент для проверки запросов на нетипизированные поля и составные типы.
Решение для временных таблиц:
Всегда явно типизируйте поля при их помещении во временные таблицы. Разберем пример правильного создания временной таблицы с явным указанием типов:
ВЫБРАТЬ
ВЫРАЗИТЬ(ИсходныеДанные.Цена КАК ЧИСЛО(15, 2)) КАК Цена,
ВЫРАЗИТЬ(ИсходныеДанные.Количество КАК ЧИСЛО(15, 3)) КАК Количество
ПОМЕСТИТЬ ВТ_ОчищенныеДанные
ИЗ
&ТаблицаИсточника КАК ИсходныеДанные
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_ОчищенныеДанные.Цена * ВТ_ОчищенныеДанные.Количество КАК Сумма
ИЗ
ВТ_ОчищенныеДанные КАК ВТ_ОчищенныеДанные
Благодаря явному приведению типов при создании временной таблицы ВТ_ОчищенныеДанные, во втором запросе пакета Конструктор без проблем позволит нам совершать любые арифметические операции над этими полями.
Иногда странное поведение Конструктора запросов связано с внутренними ошибками (багами) конкретных релизов технологической платформы «1С:Предприятие 8». Например, в некоторых версиях линеек 8.3.16 и 8.3.17 наблюдались локальные сбои в работе парсера метаданных Конфигуратора при анализе вложенных запросов и левых соединений, из-за чего валидация простых арифметических выражений завершалась ошибкой.
Если вы исключили проблемы с неразрывными пробелами и проверили типы данных, выполните следующие действия:
Столкнувшись с непонятным поведением Конструктора запросов при умножении полей, не спешите переписывать архитектуру запроса или отказываться от использования Конструктора. В 95% случаев проблема решается выполнением трех простых шагов:
* и напишите их заново вручную, чтобы избавиться от скрытых символов с кодом 160.ВЫРАЗИТЬ(... КАК ЧИСЛО) для полей, участвующих в операции.Эти несложные правила уберегут вас от потери времени при разработке запросов и позволят комфортно использовать удобный визуальный Конструктор запросов 1С без раздражающих ложных ошибок компиляции.