В практической работе разработчика 1С часто возникает задача: предоставить пользователю возможность быстрого поиска документа по его номеру. При этом пользователи обычно вводят «короткий» номер (например, «1» или «456»), тогда как в базе данных этот номер хранится в строгом формате с лидирующими нулями и префиксами (например, «0000-000001» или «ЦБ00-000456»).
В этой статье мы подробно разберем, почему попытки решать эту задачу непосредственно внутри запроса СУБД являются грубой ошибкой, и рассмотрим наиболее эффективные, профессиональные способы нормализации номера документа с использованием встроенного языка, механизмов БСП и метаданных.
Часто начинающие разработчики пытаются решить задачу «в лоб», используя конструкцию ПОДОБНО "%" + &НомерДок прямо в условии запроса. Давайте проанализируем, к чему это приводит на уровне СУБД:
% в начале шаблона поиска полностью исключает возможность использования индекса (Index Seek). СУБД будет вынуждена сканировать всю таблицу документов построчно. На крупной базе данных это приведет к зависаниям и взаимным блокировкам.Золотое правило разработки в 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"
Прописывать фиксированную длину номера в коде (так называемый «хардкод») — это частая ошибка. Если в будущем конфигурация будет дорабатываться и длину номера документа в метаданных увеличат (например, с 11 до 15 символов), ваш код перестанет работать корректно.
Давайте посмотрим, как правильно и динамически определять длину номера конкретного документа через объект метаданных:
// Получаем имя документа динамически или используем конкретный тип
ИмяДокумента = "РеализацияТоваровУслуг";
ДлинаНомераМетаданных = Метаданные.Документы[ИмяДокумента].ДлинаНомера;
ВведенныйНомер = "125";
Префикс = "0000-"; // Префикс организации/базы
// Рассчитываем, сколько нулей нужно дописать
ДлинаЗаполнителя = ДлинаНомераМетаданных - СтрДлина(Префикс);
ШаблонНулей = "";
Для Счетчик = 1 По ДлинаЗаполнителя Цикл
ШаблонНулей = ШаблонНулей + "0";
КонецЦикла;
ИскомыйНомер = Префикс + Прав(ШаблонНулей + ВведенныйНомер, ДлинаЗаполнителя);
Если вы работаете в современной типовой конфигурации (например, 1С:ERP, 1С:КА, 1С:УТ 11, 1С:Бухгалтерия 3.0), вам нет необходимости изобретать велосипед. В Библиотеке Стандартных Подсистем (БСП) уже реализованы все необходимые оптимизированные методы для работы с префиксами и номерами документов.
Рассмотрим, как решить нашу задачу с помощью общих модулей БСП:
Вместо циклов используйте готовую функцию из модуля СтроковыеФункцииКлиентСервер:
ИскомыйНомер = СтроковыеФункцииКлиентСервер.ДополнитьСтроку(ВведенныйНомер, ДлинаНомера, "0", "Слева");
Если вам, наоборот, нужно получить "чистый" номер из полного номера документа базы данных:
ПолныйНомер = "ОБ00-0000125";
// Удалит префиксы организации, базы и лидирующие нули
ЧистыйНомер = ПрефиксацияОбъектовКлиентСервер.УдалитьЛидирующиеНулиИзНомераОбъекта(ПолныйНомер);
// Результат: "125"
Если нужно быстро убрать системные префиксы БСП, оставив только содержательную часть:
НомерНаПечать = ПрефиксацияОбъектовКлиентСервер.НомерНаПечать(ПолныйНомер, Истина, Истина);
Если ваша задача состоит исключительно в том, чтобы найти и открыть документ по введенному номеру (без построения сложных отчетов и запросов с соединениями), то лучшим решением будет использование штатного метода менеджера документа.
Метод НайтиПоНомеру() оптимизирован на уровне платформы 1С и отрабатывает быстрее любого ручного запроса. При этом крайне важно помнить про периодичность нумерации документов (номера могут повторяться каждый год).
Рассмотрим пример правильного вызова этого метода:
ИскомыйНомер = "0000-000125";
ДатаПоиска = ТекущаяДата(); // Обязательно передаем дату для периодических номеров
СсылкаНаДокумент = Документы.РеализацияТоваровУслуг.НайтиПоНомеру(ИскомыйНомер, ДатаПоиска);
Если Не СсылкаНаДокумент.Пустая() Тогда
// Документ успешно найден, можем открыть форму или обработать данные
Иначе
Предупреждение("Документ с таким номером не найден!");
КонецЕсли;
Подведем итог нашего разбора. Для реализации быстрого и качественного поиска документов по номеру придерживайтесь следующих правил:
Формат() или модуль БСП СтроковыеФункцииКлиентСервер для дополнения строк лидирующими нулями.