Как найти документ по номеру без лидирующих нулей в запросе 1С?

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

В практической работе разработчика 1С часто возникает задача: предоставить пользователю возможность быстрого поиска документа по его номеру. При этом пользователи обычно вводят «короткий» номер (например, «1» или «456»), тогда как в базе данных этот номер хранится в строгом формате с лидирующими нулями и префиксами (например, «0000-000001» или «ЦБ00-000456»).

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

Почему поиск через ПОДОБНО "%..." в запросе — это плохо?

Часто начинающие разработчики пытаются решить задачу «в лоб», используя конструкцию ПОДОБНО "%" + &НомерДок прямо в условии запроса. Давайте проанализируем, к чему это приводит на уровне СУБД:

  1. Уничтожение производительности (Full Table Scan): Индексы в базах данных (в том числе по полю «Номер») строятся по принципу B-дерева слева направо. Использование символа процента % в начале шаблона поиска полностью исключает возможность использования индекса (Index Seek). СУБД будет вынуждена сканировать всю таблицу документов построчно. На крупной базе данных это приведет к зависаниям и взаимным блокировкам.
  2. Неточность поиска: Поиск по вхождению может вернуть множество лишних документов. Например, при поиске номера «12» система вернет документы с номерами «12», «112», «120», «2012» и так далее.

Золотое правило разработки в 1С: любые преобразования поисковых данных (добавление нулей, префиксов, очистка от лишних символов) всегда нужно делать до передачи параметров в запрос на стороне встроенного языка 1С. В самом запросе должно быть жесткое и точное условие: ГДЕ Документ.Номер = &Номер.

Способ 1. Приведение номера к стандартному виду функциями встроенного языка

Рассмотрим ситуацию, когда формат номера нам заранее известен. Например, номер имеет вид 0000-000001, где префикс всегда равен «0000-», а цифровая часть дополняется нулями до 6 символов. Нам нужно преобразовать введенный пользователем номер «125» в строку «0000-000125».

Разберем три варианта реализации этой логики.

Вариант А: Использование функции Формат() (Наиболее быстрый и красивый способ)

Функция Формат() позволяет мгновенно дополнить числовую строку нулями до необходимой длины с помощью конструктора форматной строки.


ВведенныйНомер = "125";
ЧисловойНомер = Число(ВведенныйНомер); // Преобразуем в число для форматирования
ИскомыйНомер = "0000-" + Формат(ЧисловойНомер, "ЧЦ=6; ЧВН=; ЧГ=0");
// Результат: "0000-000125"

Вариант Б: Использование функции Прав()

Этот способ основан на «склеивании» шаблона из нулей и введенного номера, после чего берется правая часть нужной длины. Это работает очень быстро и не требует преобразования строки в число. Для различных вариантов строковых преобразований можно использовать набор универсальных методов работы со строками в 1С.


ВведенныйНомер = "125";
НужнаяДлинаЦифровойЧасти = 6;
ШаблонНулей = "000000";

ИскомыйНомер = "0000-" + Прав(ШаблонНулей + ВведенныйНомер, НужнаяДлинаЦифровойЧасти);
// Результат: "0000-000125"

Вариант В: Цикл дополнения нулями (Классический алгоритм)

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


ВведенныйНомер = "125";
Пока СтрДлина(ВведенныйНомер) < 6 Цикл
    ВведенныйНомер = "0" + ВведенныйНомер;
КонецЦикла;

ИскомыйНомер = "0000-" + ВведенныйНомер;
// Результат: "0000-000125"

Способ 2. Динамическое определение длины номера из Метаданных

Прописывать фиксированную длину номера в коде (так называемый «хардкод») — это частая ошибка. Если в будущем конфигурация будет дорабатываться и длину номера документа в метаданных увеличат (например, с 11 до 15 символов), ваш код перестанет работать корректно.

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


// Получаем имя документа динамически или используем конкретный тип
ИмяДокумента = "РеализацияТоваровУслуг";
ДлинаНомераМетаданных = Метаданные.Документы[ИмяДокумента].ДлинаНомера;

ВведенныйНомер = "125";
Префикс = "0000-"; // Префикс организации/базы

// Рассчитываем, сколько нулей нужно дописать
ДлинаЗаполнителя = ДлинаНомераМетаданных - СтрДлина(Префикс);
ШаблонНулей = "";
Для Счетчик = 1 По ДлинаЗаполнителя Цикл
    ШаблонНулей = ШаблонНулей + "0";
КонецЦикла;

ИскомыйНомер = Префикс + Прав(ШаблонНулей + ВведенныйНомер, ДлинаЗаполнителя);

Способ 3. Профессиональный подход с использованием БСП

Если вы работаете в современной типовой конфигурации (например, 1С:ERP, 1С:КА, 1С:УТ 11, 1С:Бухгалтерия 3.0), вам нет необходимости изобретать велосипед. В Библиотеке Стандартных Подсистем (БСП) уже реализованы все необходимые оптимизированные методы для работы с префиксами и номерами документов.

Рассмотрим, как решить нашу задачу с помощью общих модулей БСП:

  1. Дополнение строки нулями слева:

    Вместо циклов используйте готовую функцию из модуля СтроковыеФункцииКлиентСервер:

    
    ИскомыйНомер = СтроковыеФункцииКлиентСервер.ДополнитьСтроку(ВведенныйНомер, ДлинаНомера, "0", "Слева");
    
  2. Очистка номера от префиксов и лидирующих нулей:

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

    
    ПолныйНомер = "ОБ00-0000125";
    // Удалит префиксы организации, базы и лидирующие нули
    ЧистыйНомер = ПрефиксацияОбъектовКлиентСервер.УдалитьЛидирующиеНулиИзНомераОбъекта(ПолныйНомер);
    // Результат: "125"
    
  3. Получение красивого номера для вывода на печать:

    Если нужно быстро убрать системные префиксы БСП, оставив только содержательную часть:

    
    НомерНаПечать = ПрефиксацияОбъектовКлиентСервер.НомерНаПечать(ПолныйНомер, Истина, Истина);
    

Способ 4. Использование стандартного метода НайтиПоНомеру()

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

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

Рассмотрим пример правильного вызова этого метода:


ИскомыйНомер = "0000-000125";
ДатаПоиска = ТекущаяДата(); // Обязательно передаем дату для периодических номеров

СсылкаНаДокумент = Документы.РеализацияТоваровУслуг.НайтиПоНомеру(ИскомыйНомер, ДатаПоиска);

Если Не СсылкаНаДокумент.Пустая() Тогда
    // Документ успешно найден, можем открыть форму или обработать данные
Иначе
    Предупреждение("Документ с таким номером не найден!");
КонецЕсли;

Резюме и рекомендации

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

← На главную