При разработке сложных обработок в 1С, особенно связанных с загрузкой данных из внешних источников (Excel, табличные документы), программисты часто сталкиваются с ситуацией, когда метод НайтиСледующий объекта ВыборкаИзРезультатаЗапроса ведет себя непредсказуемо. Казалось бы, запрос написан верно, данные в базе есть, но метод находит лишь малую часть записей. Разберем детально причины этого поведения и способы решения проблемы.
Проанализируем наиболее частую причину: несоответствие строковых значений в структуре отбора и в самой выборке. В конфигурациях, таких как 1С:Зарплата и Управление Персоналом, коды сотрудников или физических лиц могут содержать префиксы и лидирующие нули. Однако главной проблемой часто становятся обычные или неразрывные пробелы в конце строки.
Если код в справочнике имеет фиксированную длину или был импортирован с ошибками, визуально он может выглядеть идентично искомому значению, но метод НайтиСледующий вернет Ложь. Начиная с версии платформы 8.3.20, у нас появилась возможность использовать функцию СокрЛП непосредственно в тексте запроса. Рассмотрим, как это применить в коде:
// В тексте запроса обрезаем пробелы для поля поиска
Запрос.Текст =
"ВЫБРАТЬ
| Сотрудники.Ссылка КАК Сотрудник,
| Сотрудники.Код КАК ТабельныйНомер,
| СокрЛП(Сотрудники.ФизическоеЛицо.Код) КАК КодФизЛица
|ИЗ
| Справочник.Сотрудники КАК Сотрудники";
Если же ваша платформа ниже версии 8.3.20, нормализацию необходимо проводить на этапе формирования структуры поиска или в самом справочнике. Проанализируем пример подготовки структуры отбора:
ОтборКод = Новый Структура("КодФизЛица");
// Обязательно применяем СокрЛП к значению из внешнего источника
ОтборКод.КодФизЛица = СокрЛП(ТекущаяСтрокаТаблицы.Код);
ВыборкаСотрудники.Сбросить(); // Начинаем поиск с начала выборки
Если ВыборкаСотрудники.НайтиСледующий(ОтборКод) Тогда
СотрудникСсылка = ВыборкаСотрудники.Сотрудник;
КонецЕсли;
Метод НайтиСледующий осуществляет поиск, начиная с текущей позиции курсора. Выясним причину, по которой многие забывают об использовании метода Сбросить. Если вы ищете значения в цикле, то после каждого успешного (или неуспешного) поиска курсор остается на найденной записи. Чтобы следующий поиск по всей коллекции был корректным, необходимо возвращать курсор в начало.
Посмотрим на правильную организацию цикла поиска в выборке:
Для Каждого СтрокаДанных Из ТаблицаЗагрузки Цикл
Отбор = Новый Структура("ТабельныйНомер", СокрЛП(СтрокаДанных.ТН));
// Сбрасываем позицию перед каждым поиском
ВыборкаСотрудники.Сбросить();
Если ВыборкаСотрудники.НайтиСледующий(Отбор) Тогда
// Обработка результата
ОбъектДокумента.Сотрудник = ВыборкаСотрудники.Сотрудник;
Иначе
Сообщить("Не найден сотрудник с кодом: " + СтрокаДанных.ТН);
КонецЕсли;
КонецЦикла;
Проанализируем ситуацию, упомянутую в обсуждении: когда в одной базе поиск работает идеально, а в другой — выборочно. Это может быть связано с особенностями сортировки в Microsoft SQL Server. Символы дефиса ("-"), пробелы и другие спецсимволы могут по-разному интерпретироваться при индексации и упорядочивании строк в зависимости от настроек Collation базы данных.
Если в кодах физлиц используются дефисы (например, "00-0001" и "0000001"), порядок их следования в выборке может не совпадать с тем, что вы ожидаете увидеть в консоли запросов. Хотя метод НайтиСледующий теоретически должен обходить всю выборку, при отсутствии явного сброса курсора (Сбросить()) или при наличии дублей в ключевых полях, логика может давать сбои. Рекомендуется всегда добавлять УПОРЯДОЧИТЬ ПО в запрос, чтобы гарантировать стабильность выборки.
Если работа с выборкой через НайтиСледующий продолжает вызывать трудности, рассмотрим более надежные способы сопоставления данных. Выгрузка результата запроса в ТаблицуЗначений или использование Соответствия (Map) часто оказывается более эффективным решением.
Найти в ТЗ работает быстрее и не требует управления курсором.Разберем пример реализации через Соответствие:
// Выгружаем данные в соответствие для мгновенного поиска
ТаблицаРезультата = Запрос.Выполнить().Выгрузить();
КартаСотрудников = Новый Соответствие;
Для Каждого Стр Из ТаблицаРезультата Цикл
// Ключ - очищенный код, значение - ссылка
КартаСотрудников.Вставить(СокрЛП(Стр.КодФизЛица), Стр.Сотрудник);
КонецЦикла;
// Поиск в цикле загрузки
Сотрудник = КартаСотрудников.Получить(СокрЛП(КодИзФайла));
Если Сотрудник = Неопределено Тогда
// Обработка ошибки поиска
КонецЕсли;
Важно помнить, что стандартная функция СокрЛП удаляет только обычные пробелы (код 32). В кодах, скопированных из внешних систем, часто встречаются неразрывные пробелы. Выясним, как от них избавиться. Для этого можно использовать функцию СтрЗаменить, чтобы гарантировать чистоту данных перед поиском:
ЧистыйКод = СтрЗаменить(КодИзИсточника, Символы.НПП, "");
ЧистыйКод = СокрЛП(ЧистыйКод);
Подводя итог, отметим: если метод НайтиСледующий работает выборочно, в 99% случаев проблема кроется в типах данных (число против строки), скрытых символах или позиционировании курсора. Тщательная нормализация строк с помощью СокрЛП и ВЫРАЗИТЬ(... КАК СТРОКА) в запросе является лучшей практикой при работе с кодами справочников в 1С.