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