При разработке механизмов обмена данными, выгрузки на сайт или формировании выборок порциями разработчики часто прибегают к динамической сборке текста запроса. Нередко в коде встречается следующая синтаксическая ошибка платформы 1С:Предприятие:
«Неправильный псевдоним Т.Ссылка» (или аналогичное поле выборки).
Разберем детально, почему возникает данная ошибка, как платформа 1С выполняет синтаксический анализ динамического текста и какими способами можно навсегда устранить эту проблему.
Рассмотрим типовой пример формирования динамического запроса к таблице изменений для плана обмена:
ТекстЗапроса = "ВЫБРАТЬ " + ?(КоличествоЭлементов = 0, "", "Первые " + КоличествоЭлементов)
+ "
| Т.Ссылка КАК Номенклатура
|ИЗ
| Справочник." + ИмяСправочникаНоменклатура + ".Изменения КАК Т
|ГДЕ
| Т.Узел = &Узел
| И ВЫБОР КОГДА &НомерСообщения = &Неопределено ТОГДА ИСТИНА
| ИНАЧЕ Т.НомерСообщения = &НомерСообщения
| КОНЕЦ";
Если переменная КоличествоЭлементов содержит значение от 1000 и выше (например, 1000), при выполнении запроса генерируется ошибка синтаксиса. При этом попытки переименовать псевдоним таблицы или поля (например, сменить Т на Тов или проверить русскую/латинскую раскладку символов) не дают результата.
Проанализируем, как платформа 1С преобразует числовые значения в строку при конкатенации:
+ платформа неявно преобразует число в строку с учетом региональных настроек текущего сеанса. По умолчанию для чисел от 1000 применяется группировка триад с использованием неразрывного пробела (символ НПП с кодом 160)."Первые " + КоличествоЭлементов при значении 1000 превращается в строку "Первые 1 000".ВЫБРАТЬ Первые 1, где число 1 воспринимается как ограничение количества строк. Следующая часть 000 воспринимается парсером как первое поле списка выборки (числовой литерал). Идущее следом выражение Т.Ссылка парсер пытается интерпретировать как псевдоним для поля 000 (без оператора КАК), что приводит к синтаксической ошибке «Неправильный псевдоним» из-за наличия точки в имени псевдонима.Важное ограничение платформы: В языке запросов 1С число записей для конструкции ПЕРВЫЕ нельзя передать через параметры запроса (конструкция ВЫБРАТЬ ПЕРВЫЕ &Количество недопустима). Количество записей всегда должно быть жестко зашито в текст запроса как целочисленный литерал без пробелов.
Чтобы исключить появление неразрывных пробелов при формировании строки, необходимо явно отключить группировку разрядов с помощью параметра ЧГ=0 или ЧГ= в функции Формат.
Посмотрим на пример корректного формирования фрагмента запроса:
ОграничениеКоличества = ?(КоличествоЭлементов = 0, "", "ПЕРВЫЕ " + Формат(КоличествоЭлементов, "ЧГ=0") + " ");
ТекстЗапроса =
"ВЫБРАТЬ " + ОграничениеКоличества + "
| Т.Ссылка КАК Номенклатура
|ИЗ
| Справочник." + ИмяСправочникаНоменклатура + ".Изменения КАК Т
|ГДЕ
| Т.Узел = &Узел
| И ВЫБОР КОГДА &НомерСообщения = &Неопределено ТОГДА ИСТИНА
| ИНАЧЕ Т.НомерСообщения = &НомерСообщения
| КОНЕЦ";
Функция XMLСтрока преобразует базовые типы данных (в том числе числа) в канонический формат XML без форматирования, региональных стандартов и разделителей групп разрядов. Это делает её удобным инструментом для вставки чисел в тексты запросов.
Разберем пример с использованием функции XMLСтрока и метода СтрШаблон для повышения читаемости кода:
СтрокаОграничения = ?(КоличествоЭлементов = 0, "", "ПЕРВЫЕ " + XMLСтрока(КоличествоЭлементов));
ТекстЗапроса = СтрШаблон(
"ВЫБРАТЬ %1
| Т.Ссылка КАК Номенклатура
|ИЗ
| Справочник.%2.Изменения КАК Т
|ГДЕ
| Т.Узел = &Узел
| И ВЫБОР КОГДА &НомерСообщения = &Неопределено ТОГДА ИСТИНА
| ИНАЧЕ Т.НомерСообщения = &НомерСообщения
| КОНЕЦ",
СтрокаОграничения,
ИмяСправочникаНоменклатура
);
Если задача заключается исключительно в порционной выгрузке зарегистрированных изменений без сложных условий соединения таблиц, прямого запроса к таблице .Изменения можно избежать.
Платформа 1С предоставляет специализированный метод ПланыОбмена.ВыбратьИзменения, который нативно поддерживает порционную выборку данных через параметр РазмерВыборки:
// Параметры метода: Узел, НомерСообщения, Фильтр, РазмерВыборки
ВыборкаИзменений = ПланыОбмена.ВыбратьИзменения(Узел, НомерСообщения, , КоличествоЭлементов);
Пока ВыборкаИзменений.Следующий() Цикл
ДанныеОбъекта = ВыборкаИзменений.Получить();
// Обработка полученных данных
КонецЦикла;
Использование штатного метода ПланыОбмена.ВыбратьИзменения исключает необходимость динамической сборки текста запросов и защищает от ошибок парсинга строковых литералов.