В процессе интеграции систем или загрузки данных из внешних файлов (например, Excel) часто возникает ситуация, когда в источнике номер заказа указан в упрощенном виде (например, "1222"), а в базе 1С он хранится с префиксами и лидирующими нулями (например, "СФНД-001222"). В этой статье мы подробно разберем, как программно найти ссылку на документ в таких условиях, проанализируем различные подходы и выберем наиболее оптимальный с точки зрения производительности.
Самый простой и очевидный способ найти документ по части строки — использовать оператор ПОДОБНО в языке запросов 1С. Однако, как мы видим из обсуждения, часто возникают ошибки при его использовании. Разберем типичный пример. Если мы напишем условие ГДЕ Заказ.Номер ПОДОБНО &НомерДок и передадим в параметр значение "1222", запрос не вернет результат, так как он ищет полное совпадение. Для подбора записей по неполным данным также подойдёт обработка для поиска объектов по подстроке и схожести реквизитов.
Для поиска по окончанию строки необходимо использовать специальный символ %, который заменяет любую последовательность символов. Проанализируем правильный код запроса:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЗаказПокупателя.Ссылка КАК Ссылка
|ИЗ
| Документ.ЗаказПокупателя КАК ЗаказПокупателя
|ГДЕ
| ЗаказПокупателя.Номер ПОДОБНО ""%"" + &НомерИзФайла";
Запрос.УстановитьПараметр("НомерИзФайла", "1222");
РезультатЗапроса = Запрос.Выполнить();
Важный нюанс: Поиск с процентом в начале строки (%1222) делает невозможным использование индексов базы данных. Система будет вынуждена выполнить полное сканирование таблицы (Full Table Scan). Если в вашей базе сотни тысяч или миллионы документов, такой запрос будет работать крайне медленно. Рассмотрим, как можно ускорить этот процесс.
Чтобы поиск работал быстро, желательно использовать точное соответствие, которое задействует индекс по полю Номер. Для этого нам нужно преобразовать "1222" в формат 1С, добавив префикс и недостающие нули. Выясним причину, почему номера выглядят именно так: в 1С длина номера фиксирована, и она дополняется нулями до нужной длины.
Если мы заранее знаем возможные префиксы (например, "СФНД-" и "ФНД-"), мы можем подготовить список всех возможных вариантов номера. Разберем по шагам, как это сделать:
НайтиПоНомеру() или запрос с условием В.Посмотрим на пример кода с использованием функций БСП (Библиотеки стандартных подсистем):
// Предположим, номер из файла "1222", а длина номера в базе 11
ЧисловаяЧасть = "1222";
НужнаяДлина = 11;
Префиксы = Новый Массив;
Префиксы.Добавить("СФНД-");
Префиксы.Добавить("ФНД-");
ВариантыНомеров = Новый Массив;
Для Каждого Префикс Из Префиксы Цикл
// Дополняем нулями до нужной длины за вычетом длины префикса
ДлинаНулей = НужнаяДлина - СтрДлина(Префикс);
ПолныйНомер = Префикс + ПрефиксацияОбъектовКлиентСервер.ДополнитьСтрокуНулями(ЧисловаяЧасть, ДлинаНулей);
ВариантыНомеров.Добавить(ПолныйНомер);
КонецЦикла;
// Теперь ищем запросом по индексированному полю
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ Ссылка ИЗ Документ.ЗаказПокупателя ГДЕ Номер В (&ВариантыНомеров)";
Запрос.УстановитьПараметр("ВариантыНомеров", ВариантыНомеров);
Если нам не нужен запрос (например, мы обрабатываем одну строку), можно воспользоваться встроенным методом менеджера документа НайтиПоНомеру(). Рассмотрим этот вариант:
ДатаПоиска = ТекущаяДата(); // Желательно знать хотя бы год
СсылкаНаДокумент = Документы.ЗаказПокупателя.НайтиПоНомеру(СформированныйНомер, ДатаПоиска);
Если НЕ СсылкаНаДокумент.Пустая() Тогда
// Документ найден
КонецЕсли;
Обратите внимание: Поскольку нумерация в 1С чаще всего периодическая (сбрасывается каждый год), метод НайтиПоНомеру требует указания даты. Если дата неизвестна, поиск может вернуть документ за прошлый год.
Проанализируем ситуацию, когда документов миллионы, а поиск по части номера — это регулярная задача. В этом случае правильным архитектурным решением будет создание вспомогательного РегистрСведений.
Этот регистр может называться "СоответствиеНомеров" и содержать следующие измерения:
Мы можем настроить подписку на событие ПриЗаписи для нужных документов, которая будет записывать в этот регистр "чистый" номер. Тогда поиск превратится в мгновенное обращение к регистру по проиндексированному полю ЧистыйНомер. Это самый надежный способ для высоконагруженных систем.
Выясним, есть ли альтернативы, если мы не хотим менять структуру базы. В 1С существует механизм полнотекстового поиска. Если для документа включено индексирование, мы можем программно вызвать полнотекстовый поиск по строке "1222". Он работает достаточно быстро и умеет находить вхождения внутри строк.
СписокПоиска = ПолнотекстовыйПоиск.СоздатьСписок("1222", 1);
СписокПоиска.ОбластьПоиска.Добавить(Метаданные.Документы.ЗаказПокупателя);
СписокПоиска.ПерваяПорция();
Если СписокПоиска.Количество() > 0 Тогда
Результат = СписокПоиска[0].Значение; // Это и будет наша ссылка
КонецЕсли;
Однако помните, что полнотекстовый поиск зависит от актуальности индекса, который обновляется регламентным заданием.
Для разовых задач на небольших базах вполне подойдет оператор ПОДОБНО с использованием символа %. Если же вы работаете в крупной компании с большим объемом данных, мы рекомендуем либо программно восстанавливать префиксы для точного поиска, либо внедрять вспомогательный регистр сведений. Также всегда учитывайте периодичность нумерации: старайтесь ограничивать поиск по дате, чтобы не получить ссылку на старый заказ с тем же номером.