Как в запросе выполнить поиск по коду, если во входных данных отсутствуют ведущие нули?

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

В практике разработчика 1С часто возникает ситуация, когда внешние системы или пользователи предоставляют идентификаторы (например, табельные номера, коды артикулов или номера документов) в «чистом» числовом виде без ведущих нулей. Однако в самой базе 1С коды справочников обычно имеют текстовый тип и содержат дополнение нулями слева (например, «0000000123» вместо «123»). Поиск по прямому соответствию в этом случае не даст результатов, так как для строкового типа значения "123" и "0000000123" не являются эквивалентными.

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

Способ 1. Программная подготовка искомых значений (Рекомендуемый)

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

Разберем по шагам, как дополнить номер нулями, зная требуемую длину кода из метаданных:


// Получаем длину кода справочника из метаданных
ДлинаКода = Метаданные.Справочники.Сотрудники.ДлинаКода;

// Исходный номер без нулей (например, "123")
ВходнойНомер = "123";

// Формируем строку с ведущими нулями
// ЧГ=0 (без группировки разрядов), ЧВН= (с ведущими нулями), ЧЦ= (общая длина)
НужныйКод = Формат(Число(ВходнойНомер), "ЧГ=0; ЧВН=; ЧЦ=" + ДлинаКода);

// Теперь НужныйКод выглядит как "0000000123" и его можно передать в параметр запроса
Запрос.УстановитьПараметр("КодДляПоиска", НужныйКод);

Если нам нужно обработать целый список (массив) табельных номеров, мы воспользуемся циклом:


МассивКодовСНулями = Новый Массив;
ДлинаКода = Метаданные.Справочники.Сотрудники.ДлинаКода;

Для Каждого ТекНомер Из МассивВходныхНомеров Цикл
    МассивКодовСНулями.Добавить(Формат(Число(ТекНомер), "ЧГ=0; ЧВН=; ЧЦ=" + ДлинаКода));
КонецЦикла;

Запрос.УстановитьПараметр("СписокКодов", МассивКодовСНулями);
// В запросе используем: ГДЕ Сотрудники.Код В (&СписокКодов)

Способ 2. Использование оператора ПОДОБНО (LIKE)

Рассмотрим ситуацию, когда мы не знаем точного количества нулей или когда код может содержать префиксы. В таких случаях можно использовать оператор ПОДОБНО. Однако стоит помнить: использование символа маски "%" в начале строки (например, "%123") заставляет систему игнорировать индексы и выполнять полное сканирование таблицы (Full Table Scan), что существенно замедляет работу.

Если мы точно знаем, что перед числом идут только нули, можно использовать конструкцию:


Запрос.Текст = 
    "ВЫБРАТЬ
    |   Сотрудники.Ссылка
    |ИЗ
    |   Справочник.Сотрудники КАК Сотрудники
    |ГДЕ
    |   Сотрудники.Код ПОДОБНО ""%"" + &ВходнойНомер";

Проанализируем риски: при таком подходе под условие могут попасть не только "0000000123", но и "0000001123" или "БП-0000123". Если это допустимо, метод можно использовать. Если же нужно использовать ПОДОБНО для списка значений, помните, что в языке запросов 1С нельзя напрямую использовать В (ПОДОБНО...). Придется либо объединять условия через ИЛИ, либо использовать временные таблицы.

Способ 3. Преобразование кода внутри запроса

Выясним, как можно «доклеить» нули прямо в тексте запроса. Это менее эффективно, чем подготовка параметра, но иногда удобно при соединении двух таблиц в одном запросе. Мы можем использовать функции ПРАВ и сложение строк. Суть метода: приклеить к коду заведомо большое количество нулей, а затем обрезать строку справа до нужной длины.


// Пример для длины кода 10 знаков
Запрос.Текст = 
    "ВЫБРАТЬ
    |   Сотрудники.Ссылка
    |ИЗ
    |   Справочник.Сотрудники КАК Сотрудники
    |ГДЕ
    |   Сотрудники.Код = ПРАВ(""0000000000"" + &ВходнойНомер, 10)";

Важный момент: В данном примере &ВходнойНомер должен быть строкой. Если это число, его предварительно нужно привести к строке. В языке запросов 1С нет функции ЧислоВСтроку, поэтому манипуляции лучше проводить над строковыми данными.

Способ 4. Современные функции платформы (версии 8.3.20+)

В современных версиях платформы появились расширенные возможности работы со строками в запросах. Разберем, как можно использовать функции ДЛИНАСТРОКИ и ПОДСТРОКА для более гибкого поиска. Хотя прямого аналога функции «дополнить нулями» в запросе до сих пор нет, мы можем использовать конструкцию ВЫБОР для разных длин входящих строк:


// Пример логики для обработки строк разной длины
Запрос.Текст = 
    "ВЫБРАТЬ
    |   Сотрудники.Ссылка
    |ИЗ
    |   Справочник.Сотрудники КАК Сотрудники
    |ГДЕ
    |   Сотрудники.Код = ВЫБОР
    |       КОГДА ДЛИНАСТРОКИ(&ВходнойНомер) = 1 ТОГДА ""000000000"" + &ВходнойНомер
    |       КОГДА ДЛИНАСТРОКИ(&ВходнойНомер) = 2 ТОГДА ""00000000"" + &ВходнойНомер
    |       ...
    |       ИНАЧЕ &ВходнойНомер
    |   КОНЕЦ";

Такой подход выглядит громоздко, поэтому мы вновь возвращаемся к мысли, что подготовка данных на стороне 1С (в коде модуля) является приоритетной.

Способ 5. Оптимизация через числовое представление

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

Посмотрим на преимущества:

  1. Поиск по числу выполняется значительно быстрее, чем по строке.
  2. Индекс по числовому полю занимает меньше места.
  3. В запросе не нужно выполнять никаких манипуляций со строками:

Запрос.Текст = 
    "ВЫБРАТЬ
    |   Сотрудники.Ссылка
    |ИЗ
    |   Справочник.Сотрудники КАК Сотрудники
    |ГДЕ
    |   Сотрудники.КодЧислом = &ВходнойНомерЧислом";

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

Проанализировав все варианты, подведем итоги:

Таким образом, мы выяснили, что наиболее эффективным решением является «приведение к общему знаменателю» данных еще до момента их попадания в текст запроса.

← На главную