Как найти номенклатуру по наименованию в 1С и получить ссылку на элемент?

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

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

Разбор ошибки: почему возникает «Поле объекта не обнаружено»

Проанализируем исходную проблему. При реализации поиска через запрос разработчики часто допускают ошибку несовпадения полей в секции ВЫБРАТЬ и при обращении к результату выборки. Посмотрим на ошибочный фрагмент кода:


// ОШИБКА: в секции ВЫБРАТЬ указано только Наименование,
// а при обращении к выборке запрашивается поле Номенклатура или Ссылка
Запрос.Текст = "ВЫБРАТЬ
               |    Номенклатура.Наименование
               |ИЗ
               |    Справочник.Номенклатура КАК Номенклатура
               |ГДЕ
               |    Номенклатура.Наименование ПОДОБНО &Наименование";
...
Если ВыборкаДетальныеЗаписи.Следующий() Тогда
    Возврат ВыборкаДетальныеЗаписи.Номенклатура; // Вызовет ошибку "Поле объекта не обнаружено"
КонецЕсли;

Выборка из результата запроса содержит исключительно те поля, которые были явно перечислены в секции ВЫБРАТЬ. Если поле Ссылка не указано в запросе, обратиться к нему через ВыборкаДетальныеЗаписи.Ссылка невозможно. Поля с именем таблицы (Номенклатура) в выборке также не существует, если только для него не был задан соответствующий псевдоним.

Способ 1. Поиск номенклатуры с помощью запроса

Разберем корректную реализацию функции поиска через объект Запрос. Для получения ссылки необходимо явно указать поле Номенклатура.Ссылка в запросе. Для предотвращения неоднозначности, если найдено несколько совпадений, рекомендуется использовать конструкцию ВЫБРАТЬ ПЕРВЫЕ 1.


Функция ПолучитьСсылкуНоменклатуры(ТекстПоиска) Экспорт

    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ ПЕРВЫЕ 1
        |    Номенклатура.Ссылка КАК Ссылка
        |ИЗ
        |    Справочник.Номенклатура КАК Номенклатура
        |ГДЕ
        |    Номенклатура.Наименование ПОДОБНО &Наименование
        |УПОРЯДОЧИТЬ ПО
        |    Номенклатура.ЭтоГруппа,
        |    Номенклатура.Наименование";
    
    // При использовании ПОДОБНО можно искать как точное совпадение, так и подстроку:
    Запрос.УстановитьПараметр("Наименование", ТекстПоиска);
    
    РезультатЗапроса = Запрос.Выполнить();
    Выборка = РезультатЗапроса.Выбрать();
    
    Если Выборка.Следующий() Тогда
        Возврат Выборка.Ссылка;
    Иначе
        Возврат Справочники.Номенклатура.ПустаяСсылка();
    КонецЕсли;

КонецФункции

Рассмотрим важные особенности работы с оператором ПОДОБНО в запросах:

  1. Поиск подстроки: Если требуется найти элемент, содержащий искомый текст в любой части наименования, в параметр передается строка с масками: "%" + СокрЛП(ТекстПоиска) + "%".
  2. Использование индексов: Конструкция ПОДОБНО "%..." отключает использование индекса по наименованию в СУБД, что приводит к полному сканированию таблицы (Table Scan). Для быстрого и точного поиска по индексу следует использовать прямое равенство ГДЕ Номенклатура.Наименование = &Наименование.
  3. Экранирование спецсимволов: Если в наименовании номенклатуры содержатся символы %, _, [ или ], они воспринимаются оператором ПОДОБНО как спецсимволы шаблона. В таких случаях необходимо использовать ключевое слово СПЕЦСИМВОЛ для их экранирования.

Способ 2. Использование встроенного метода НайтиПоНаименованию

Если требуется выполнить быстрый поиск одиночного элемента без написания текста запроса, воспользуемся методом менеджера справочника НайтиПоНаименованию(). Этот метод оптимизирован платформой и работает быстрее простого запроса.


Функция НайтиНоменклатуруПоИмени(ТекстПоиска) Экспорт

    // Синтаксис: НайтиПоНаименованию(Наименование, ТочноеСоответствие, Родитель, Владелец)
    // Второй параметр (ТочноеСоответствие) по умолчанию равен Ложь (поиск по началу строки).
    // Для строгого поиска обязательно передаем Истина:
    
    СсылкаНоменклатуры = Справочники.Номенклатура.НайтиПоНаименованию(СокрЛП(ТекстПоиска), Истина);
    
    Возврат СсылкаНоменклатуры; // Если элемент не найден, вернется ПустаяСсылка

КонецФункции

Обратим внимание: если параметр ТочноеСоответствие не указан или равен Ложь, платформа выполнит поиск по вхождению строки с начала наименования, что может привести к выбору не того элемента (например, при поиске «Болт» будет найден «Болт М8х20»).

Очистка и подготовка данных при загрузке из Excel

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

  1. Неразрывные пробелы: При выгрузках из внешних программ в тексте часто присутствуют неразрывные пробелы (символ с кодом 160 / Символы.НПП). Функция СокрЛП() удаляет только стандартные пробелы (код 32). Перед поиском обязательно очистим строку:
    
    ТекстОчищенный = СтрЗаменить(ТекстЯчейки, Символы.НПП, " ");
    ТекстОчищенный = СокрЛП(ТекстОчищенный);
    
  2. Ограничение длины наименования: В конфигурации реквизит Наименование имеет фиксированную максимальную длину (например, 100 или 150 символов). Если наименование в файле длиннее, точное сравнение вернет ложный результат. Рекомендуется обрезать входящую строку с помощью функции Лев() под длину реквизита.

Оптимизация при пакетной загрузке большого объема данных

Вызов запроса или метода НайтиПоНаименованию() в цикле для каждой строки загружаемого файла существенно замедляет процесс импорта. Разберем правильный подход к массовой загрузке:

  1. Соберем все уникальные наименования из файла в массив.
  2. Выполним один пакетный запрос с условием ГДЕ Номенклатура.Наименование В (&МассивНаименований).
  3. Выгрузим результат запроса в объект Соответствие, где ключом будет наименование, а значением — найденная ссылка.
  4. При обходе строк таблицы сопоставим данные через быстрое обращение к созданному соответствию в оперативной памяти.

Создание нового элемента при отсутствии совпадений

Если в процессе проверки функция вернула пустую ссылку, создадим новый элемент справочника программно. Проанализируем пример корректного заполнения обязательных реквизитов:


Если Не ЗначениеЗаполнено(СсылкаНоменклатуры) Тогда

    НовыйОбъект = Справочники.Номенклатура.СоздатьЭлемент();
    НовыйОбъект.Наименование = ТекстОчищенный;
    
    // Обязательно заполняем системные и учетные реквизиты,
    // необходимые для проведения документов:
    НовыйОбъект.ВидНоменклатуры = Справочники.ВидыНоменклатуры.Товар;
    НовыйОбъект.БазоваяЕдиницаИзмерения = Справочники.КлассификаторЕдиницИзмерения.Штука;
    НовыйОбъект.СтавкаНДС = Перечисления.СтавкиНДС.НДС20;
    
    Попытка
        НовыйОбъект.Записать();
        СсылкаНоменклатуры = НовыйОбъект.Ссылка;
    Исключение
        Сообщить("Не удалось записать номенклатуру: " + ОписаниеОшибки());
    КонецПопытки;

КонецЕсли;

Таким образом, для надежного поиска и сопоставления номенклатуры важно корректно формировать поля выборки в запросах, предварительно очищать входящие текстовые данные от скрытых символов и учитывать особенности индексации строковых полей в платформе 1С.

← На главную