К статье
Практический материал

Разработка и Конфигурация · 10 мин

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

Способы найти элемент справочника 1С по нескольким реквизитам: НайтиПоРеквизиту, запрос, выборка. Примеры кода, проверка результата, типичные ошибки.

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

Выбор способа зависит от трёх факторов: сколько реквизитов участвует в отборе, как часто выполняется поиск и насколько критична скорость. Ниже разобраны рабочие варианты с примерами кода, проверкой результата и типичными ошибками, которые приводят к дублям элементов или ложному результату «не найдено».

Что учесть перед выбором способа поиска

Прежде чем писать код, ответьте на три вопроса. Первый — участвуют ли в отборе только реквизиты шапки справочника или также табличные части и дополнительные реквизиты (БСП). Второй — нужен один элемент или потенциально несколько совпадений. Третий — выполняется поиск разово (например, при загрузке файла) или в цикле по тысячам строк.

Для разового поиска разница между методами незаметна. В цикле обработки большого файла неоптимальный способ увеличит время выполнения в десятки раз: запрос внутри цикла — самая дорогая ошибка. В таких случаях данные справочника выгружают заранее в соответствие или таблицу значений и ищут уже в памяти.

Один реквизитНайтиПоРеквизиту()

Метод доступен только для реквизитов с признаком индексирования

Несколько реквизитовЗапрос или Выбрать()

Запрос гибче, выборка проще для простых условий

Поиск в циклеКэширование в соответствие

Один запрос до цикла вместо запроса на каждой итерации

Доп. реквизиты БСПЗапрос к ТЧ ДополнительныеРеквизиты

Обычный отбор по ним невозможен напрямую

Поиск по одному реквизиту: НайтиПоРеквизиту

Базовый метод менеджера справочника ищет элемент по значению одного реквизита. Важное ограничение: метод доступен только для реквизитов, у которых в конфигураторе включено индексирование (свойство «Индексировать»). Если индекса нет, попытка вызова завершится ошибкой.

НайденнаяСсылка = Справочники.Номенклатура.НайтиПоРеквизиту("Артикул", "АРТ-10452");

Если НайденнаяСсылка.Пустая() Тогда

// элемент не найден — создаём новый или сообщаем об ошибке

КонецЕсли;

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

Поиск по нескольким реквизитам через запрос

Универсальный и рекомендуемый способ — запрос с условиями по всем нужным реквизитам. Он не требует индексов по каждому полю (хотя индексы ускоряют выполнение), позволяет задавать сложные условия и сразу получать нужные поля без обращения к базе повторно.

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ ПЕРВЫЕ 1

| Контрагенты.Ссылка КАК Ссылка

|ИЗ

| Справочник.Контрагенты КАК Контрагенты

|ГДЕ

| Контрагенты.ИНН = &ИНН

| И Контрагенты.КПП = &КПП

| И НЕ Контрагенты.ПометкаУдаления";

Запрос.УстановитьПараметр("ИНН", ИНН);

Запрос.УстановитьПараметр("КПП", КПП);

Выборка = Запрос.Выполнить().Выбрать();

Если Выборка.Следующий() Тогда

НайденнаяСсылка = Выборка.Ссылка;

Иначе

// элемент не найден

КонецЕсли;

Обратите внимание на три приёма в примере. ПЕРВЫЕ 1 ограничивает выборку одной записью — сервер не перебирает остальные совпадения. Параметры передаются через УстановитьПараметр, а не конкатенацией строки — это защищает от ошибок с типами и кавычками. Условие НЕ ПометкаУдаления отсекает помеченные на удаление элементы, которые обычно не должны подставляться в документы.

Поиск через Выбрать() с отбором

Метод Выбрать() менеджера справочника принимает структуру отбора, где ключ — имя реквизита, значение — искомое значение. Это короткий способ без написания текста запроса, но с ограничениями: в отбор можно включать только реквизиты с индексированием, и условия всегда соединяются по «И» на равенство.

Отбор = Новый Структура;

Отбор.Вставить("Организация", ОрганизацияСсылка);

Отбор.Вставить("НомерДоговора", "145/-П");

Выборка = Справочники.ДоговорыКонтрагентов.Выбрать( , , Отбор);

Пока Выборка.Следующий() Цикл

НайденнаяСсылка = Выборка.Ссылка;

Прервать;

КонецЦикла;

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

Поиск в цикле без потери производительности

Классическая ошибка при загрузке данных — вызывать запрос поиска на каждой строке файла. При десятках тысяч строк это даёт десятки тысяч обращений к СУБД. Правильный подход — один запрос до цикла, который выгружает нужные реквизиты справочника, и поиск в оперативной памяти.

// Один запрос до цикла

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Т.ИНН КАК ИНН,

| Т.КПП КАК КПП,

| Т.Ссылка КАК Ссылка

|ИЗ Справочник.Контрагенты КАК Т

|ГДЕ НЕ Т.ПометкаУдаления";

КэшКонтрагентов = Новый Соответствие;

Выборка = Запрос.Выполнить().Выбрать();

Пока Выборка.Следующий() Цикл

Ключ = Выборка.ИНН + "|" + Выборка.КПП;

КэшКонтрагентов.Вставить(Ключ, Выборка.Ссылка);

КонецЦикла;

// Внутри цикла загрузки — поиск в памяти

Ключ = СокрЛП(СтрокаФайла.ИНН) + "|" + СокрЛП(СтрокаФайла.КПП);

НайденнаяСсылка = КэшКонтрагентов[Ключ];

Ключ соответствия строится конкатенацией реквизитов через разделитель, которого не встретится в данных. Такой подход ускоряет обработку на порядки, но требует памяти: для справочника в сотни тысяч элементов оцените объём выгружаемых полей — берите только реквизиты ключа и ссылку.

Порядок действий при поиске по нескольким реквизитам
  1. 1
    Определите точный состав реквизитов, однозначно идентифицирующих элемент
  2. 2
    Напишите запрос с условиями ГДЕ по всем реквизитам и ПЕРВЫЕ 1
  3. 3
    Добавьте условие НЕ ПометкаУдаления, если помеченные элементы не нужны
  4. 4
    Передайте значения через УстановитьПараметр, предварительно применив СокрЛП к строкам
  5. 5
    Проверьте результат: Выборка.Следующий() вернула Истина или ссылка не пустая
  6. 6
    При отсутствии элемента — создайте новый или зафиксируйте ошибку в журнале

Проверка результата и обработка дублей

Найденная ссылка — не гарантия корректности. Две проверки обязательны: ссылка не пустая (элемент найден) и совпадение ровно одно (нет дублей). Дубли по ключевым реквизитам — частая проблема в базах, где уникальность не контролировалась, и поиск «первого попавшегося» молча подставляет не тот элемент.

Контрольные точки

Как проверить результат поиска

Значение результата
Норма

Ссылка не пустая, элемент открывается

Тревожный признак

Пустая ссылка — элемент не найден

Количество совпадений
Норма

Ровно один элемент по набору реквизитов

Тревожный признак

Несколько элементов — нужна обработка дублей

Пометка удаления
Норма

Элемент активен

Тревожный признак

Элемент помечен на удаление, но подставился в документ

Данные найденного
Норма

Реквизиты совпадают с исходными значениями

Тревожный признак

Найден похожий элемент с отличающимися данными

Для контроля дублей выполните запрос с группировкой по реквизитам ключа и условием ИМЕЮЩИЕ КОЛИЧЕСТВО(*) > 1. Найденные группы — кандидаты на объединение штатной обработкой поиска и удаления дублей. До устранения дублей любой программный поиск по этим реквизитам ненадёжен.

Поиск по дополнительным реквизитам и табличным частям

Дополнительные реквизиты в конфигурациях на БСП хранятся в табличной части «ДополнительныеРеквизиты», поэтому отбор Выбрать() по ним невозможен. Поиск выполняется запросом с соединением основной таблицы и табличной части по значению и свойству.

Запрос.Текст =

"ВЫБРАТЬ ПЕРВЫЕ 1

| ДопРеквизиты.Ссылка КАК Ссылка

|ИЗ

| Справочник.Номенклатура.ДополнительныеРеквизиты КАК ДопРеквизиты

|ГДЕ

| ДопРеквизиты.Свойство = &Свойство

| И ДопРеквизиты.Значение = &Значение";

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

Типичные ошибки
01
Вызов НайтиПоРеквизиту для реквизита без индексирования — ошибка выполнения
02
Запрос внутри цикла загрузки — кратное замедление обработки
03
Отсутствие СокрЛП перед сравнением строк — ложный результат «не найден» и создание дублей
04
Игнорирование пометки удаления — в документы подставляются удалённые элементы
05
Отсутствие проверки на дубли — подставляется первый попавшийся из нескольких элементов
06
Конкатенация значений прямо в текст запроса — ошибки на кавычках и риск некорректных данных

Частые вопросы

Можно ли передать несколько реквизитов в НайтиПоРеквизиту?

Нет, метод принимает только один реквизит. Для нескольких условий используйте запрос или Выбрать() со структурой отбора. Альтернатива — последовательное сужение: найти по одному реквизиту, затем проверить остальные у найденного объекта, но это уместно только при гарантированно малом числе совпадений.

Что вернёт поиск, если элементов несколько?

НайтиПоРеквизиту и запрос с ПЕРВЫЕ 1 вернут один произвольный элемент из совпавших — какой именно, не гарантируется. Если дубли возможны, сначала проверьте их количество запросом с группировкой и устраните, иначе результат поиска непредсказуем.

Как искать без учёта регистра и пробелов?

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

Нужно ли включать индексирование реквизитов?

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

Как найти элемент по реквизиту составного типа?

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

Чем поиск в толстом и тонком клиенте отличается?

Сам код поиска одинаков, но выполнять его следует на сервере (в серверной процедуре или модуле менеджера). Вызов запросов с клиента в тонком клиенте невозможен напрямую — оформляйте поиск серверной процедурой с директивой &НаСервере.

Итог

Что важно запомнить

По нескольким реквизитам элемент справочника ищут запросом с условиями ГДЕ или выборкой со структурой отбора; НайтиПоРеквизиту работает только с одним индексированным реквизитом. Всегда проверяйте результат на пустоту и дубли, исключайте помеченные на удаление элементы, а в циклах кэшируйте данные справочника одним запросом до начала обработки.