Как исправить ошибку левого соединения в запросе 1С и обновить данные номенклатуры?

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

При разработке обработок загрузки данных из внешних источников (например, из файлов Excel) начинающие разработчики часто сталкиваются с синтаксическими ошибками в тексте запроса. Одной из распространенных является ошибка вида «{(17, 2)}: Ожидается выражение "ВЫБРАТЬ"» при попытке связать загруженные данные со справочником в базе. Разберем причины возникновения этой ошибки, выясним типичные заблуждения при написании запросов и рассмотрим правильный пошаговый алгоритм сопоставления и обновления данных в 1С.

Основные ошибки при построении запроса

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

  1. Некорректная конструкция соединения: В языке запросов 1С соединение (ЛЕВОЕ СОЕДИНЕНИЕ, ПОЛНОЕ СОЕДИНЕНИЕ, ВНУТРЕННЕЕ СОЕДИНЕНИЕ) возможно только между таблицами, а не отдельными полями или реквизитами. Кроме того, условие связи всегда задается ключевым словом ПО, а не конструкциями через точку или операторы И.
  2. Ошибочные псевдонимы полей: Псевдоним поля (после ключевого слова КАК) не может содержать точку (например, конструкция вида КАК НоваяСтрока.ОписаниеТовара является недопустимой). Псевдоним должен быть простым идентификатором.
  3. Лишняя точка с запятой: Точка с запятой в тексте запроса разделяет отдельные пакеты. Установка символа ; непосредственно перед секцией ЛЕВОЕ СОЕДИНЕНИЕ приводит к тому, что платформа воспринимает соединение как начало нового пакета и выдает ошибку ожидания ключевого слова ВЫБРАТЬ.
  4. Попытка прямого обращения к табличной части формы в секции ИЗ: Нельзя напрямую обращаться к реквизитам объекта или формы (например, Объект.ДанныеПоискаИзExcel) в тексте запроса. Табличную часть необходимо предварительно выгрузить в объект ТаблицаЗначений и передать в запрос через параметр.
  5. Синтаксис вызова метода выполнения: Метод Выполнить() является функцией объекта Запрос и требует круглых скобок. Конструкция Запрос.Выполнить.Выгрузить вызывает синтаксическую ошибку времени выполнения. Корректный синтаксис: Запрос.Выполнить().Выгрузить() или Запрос.Выполнить().Выбрать().
  6. Запросы в 1С работают только на чтение: Язык запросов 1С является аналогом оператора SELECT в SQL. Изменить или записать данные в базу напрямую из текста запроса невозможно — модификация реквизитов объектов выполняется через объектную модель после получения выборки.

Шаг 1. Подготовка и передача таблицы значений в запрос

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


ТаблицаДляЗапроса = Объект.ДанныеПоискаИзExcel.Выгрузить();

// Рекомендуется удалить лишние пробелы в полях поиска
Для Каждого Стр Из ТаблицаДляЗапроса Цикл
    Стр.Артикул = СокрЛП(Стр.Артикул);
    Стр.Производитель = СокрЛП(Стр.Производитель);
КонецЦикла;

Шаг 2. Формирование пакетного запроса с левым соединением

Посмотрим на правильную структуру пакетного запроса. В первом пакете мы помещаем переданную таблицу во временную таблицу и индексируем поля, по которым будет выполняться сопоставление. Во втором пакете соединяем временную таблицу со справочником Номенклатура по полям Артикул и Производитель.


Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;

Запрос.Текст = 
"ВЫБРАТЬ
|	ВремТаб.Артикул КАК Артикул,
|	ВремТаб.Производитель КАК Производитель,
|	ВремТаб.СсылкаНаКартинку КАК СсылкаНаКартинку,
|	ВремТаб.ОписаниеТовара КАК ОписаниеТовара
|ПОМЕСТИТЬ ВТ_ДанныеExcel
|ИЗ
|	&ВремТаб КАК ВремТаб
|ИНДЕКСИРОВАТЬ ПО
|	Артикул,
|	Производитель
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
|	СпрНоменклатура.Ссылка КАК СсылкаНоменклатура,
|	ВТ_ДанныеExcel.СсылкаНаКартинку КАК СсылкаНаКартинку,
|	ВТ_ДанныеExcel.ОписаниеТовара КАК ОписаниеТовара
|ИЗ
|	ВТ_ДанныеExcel КАК ВТ_ДанныеExcel
|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК СпрНоменклатура
|		ПО ВТ_ДанныеExcel.Артикул = СпрНоменклатура.Артикул
|			И ВТ_ДанныеExcel.Производитель = СпрНоменклатура.Производитель
|ГДЕ
|	НЕ СпрНоменклатура.ПометкаУдаления";

Запрос.УстановитьПараметр("ВремТаб", ТаблицаДляЗапроса);
РезультатЗапроса = Запрос.Выполнить();

Обратим внимание: если требуется найти только те позиции, которые гарантированно есть в базе, используется ВНУТРЕННЕЕ СОЕДИНЕНИЕ. Если же необходимо сохранить все строки загружаемой таблицы независимо от наличия номенклатуры в базе — применяется ЛЕВОЕ СОЕДИНЕНИЕ.

Шаг 3. Обход выборки и запись данных в справочник

Разберем, как применить полученные результаты для изменения элементов справочника. Мы обходим выборку, получаем объект номенклатуры, заполняем реквизиты и записываем изменения. Для повышения производительности при больших объемах данных используем механизм транзакций.


Выборка = РезультатЗапроса.Выбрать();

Счетчик = 0;
НачатьТранзакцию();

Попытка
    Пока Выборка.Следующий() Цикл
        
        Если ЗначениеЗаполнено(Выборка.СсылкаНоменклатура) Тогда
            ОбъектНоменклатура = Выборка.СсылкаНоменклатура.ПолучитьОбъект();
            
            Модифицирован = Ложь;
            
            Если ОбъектНоменклатура.Описание <> Выборка.ОписаниеТовара Тогда
                ОбъектНоменклатура.Описание = Выборка.ОписаниеТовара;
                Модифицирован = Истина;
            КонецЕсли;
            
            Если ОбъектНоменклатура._ПутьКартинкамНаСайте <> Выборка.СсылкаНаКартинку Тогда
                ОбъектНоменклатура._ПутьКартинкамНаСайте = Выборка.СсылкаНаКартинку;
                Модифицирован = Истина;
            КонецЕсли;
            
            Если Модифицирован Тогда
                ОбъектНоменклатура.Записать();
                Счетчик = Счетчик + 1;
            КонецЕсли;
            
            // Фиксация порциями для снижения нагрузки на блокировки
            Если Счетчик % 200 = 0 Тогда
                ЗафиксироватьТранзакцию();
                НачатьТранзакцию();
            КонецЕсли;
        КонецЕсли;
        
    КонецЦикла;
    
    ЗафиксироватьТранзакцию();
    
Исключение
    ОтменитьТранзакцию();
    ВызватьИсключение;
КонецПопытки;

Рекомендации по разработке запросов

Чтобы избежать подобных ошибок в дальнейшем, рекомендуем придерживаться следующих правил:

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