Как найти основное средство в регистре сведений по инвентарному номеру из Excel при несовпадении формата?

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

При загрузке данных из внешних таблиц Excel часто возникает проблема несовпадения форматов строковых идентификаторов. Например, инвентарный номер в регистре сведений ПервоначальныеСведенияОСБухгалтерскийУчет может храниться как 00001398 или 00101398, тогда как из Excel считывается число 1398. При этом длина номеров в базе может быть разной, а прямое использование условий с ПОДОБНО (LIKE) либо запрещено требованиями к производительности, либо приводит к ложным срабатываниям.

Разберем причины этой проблемы, возможные подводные камни и несколько эффективных способов сопоставления данных на платформе 1С:Предприятие.

Почему возникают сложности сопоставления?

Проанализируем основные технические особенности и риски при работе с инвентарными номерами:

  1. Ограничения языка запросов 1С: В запросах 1С отсутствуют функции динамического отсечения произвольного числа лидирующих символов (аналоги LTRIM с параметром или регулярных выражений). Нельзя прямо в запросе безопасно урезать только нули слева.
  2. Опасность функции СтрЗаменить: Попытка очистить нули через простую замену всех символов «0» на пустую строку приведет к искажению данных: номер 00001098 превратится в 198, что нарушит уникальность и сопоставление.
  3. Разная разрядность номеров: Если номера заводились вручную или переносились из разных исторических баз, их длина может колебаться от 5 до 9 знаков. Простое дополнение нулями до фиксированной длины не всегда дает стопроцентный результат.
  4. Производительность: Поле ИнвентарныйНомер в типовых регистрах сведений бухгалтерского учета ОС чаще всего является ресурсом, а не измерением. Выполнение запросов с неточным поиском в цикле для каждой строки файла Excel приведет к критическому замедлению загрузки.

Способ 1. Формирование массива потенциальных номеров для запроса

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

Разберем по шагам алгоритм подготовки данных:

  1. Определим максимальную длину поля инвентарного номера через объект Метаданные.
  2. Приведем входное значение из Excel к строковому виду без разделителей групп.
  3. Сформируем массив вариантов номера, последовательно добавляя нули слева вплоть до максимальной длины.
  4. Выполним запрос с условием вхождения в массив ГДЕ ИнвентарныйНомер В (&МассивПотенциальныхНомеров).

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


ДлинаНомераВРегистре = Метаданные.РегистрыСведений.ПервоначальныеСведенияОСБухгалтерскийУчет.Ресурсы.ИнвентарныйНомер.Тип.КвалификаторыСтроки.Длина;
МассивПотенциальныхНомеров = Новый Массив;

Если ТипЗнч(НомерИзЭксель) = Тип("Число") Тогда
    СтрИнвентарныйНомер = Формат(НомерИзЭксель, "ЧГ=0");
Иначе
    СтрИнвентарныйНомер = Прав(СокрЛП(НомерИзЭксель), ДлинаНомераВРегистре);
КонецЕсли;

МассивПотенциальныхНомеров.Добавить(СтрИнвентарныйНомер);

Пока СтрДлина(СтрИнвентарныйНомер) < ДлинаНомераВРегистре Цикл
    СтрИнвентарныйНомер = "0" + СтрИнвентарныйНомер;
    МассивПотенциальныхНомеров.Добавить(СтрИнвентарныйНомер);
КонецЦикла;

Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   СрезПоследних.ОсновноеСредство КАК ОсновноеСредство,
    |   СрезПоследних.ИнвентарныйНомер КАК ИнвентарныйНомер
    |ИЗ
    |   РегистрСведений.ПервоначальныеСведенияОСБухгалтерскийУчет.СрезПоследних(, ИнвентарныйНомер В (&МассивПотенциальныхНомеров)) КАК СрезПоследних";

Запрос.УстановитьПараметр("МассивПотенциальныхНомеров", МассивПотенциальныхНомеров);
РезультатЗапроса = Запрос.Выполнить();

Способ 2. Нормализация через функции БСП и кэширование в памяти

Если в файле Excel содержится большое количество строк, выполнять отдельные запросы для каждой позиции неэффективно. Оптимальным решением будет однократное чтение данных регистра в память с последующей нормализацией инвентарных номеров через быстрый поиск в объекте Соответствие.

Для корректного удаления только лидирующих нулей используем штатные функции Библиотеки стандартных подсистем (БСП): ПрефиксацияОбъектовКлиентСервер.УдалитьЛидирующиеНули или СтроковыеФункцииКлиентСервер.УдалитьСимволыСлева.

Рассмотрим пример реализации пакетного сопоставления:


// 1. Получаем все актуальные сведения об ОС единым запросом
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   СрезПоследних.ОсновноеСредство КАК ОсновноеСредство,
    |   СрезПоследних.ИнвентарныйНомер КАК ИнвентарныйНомер
    |ИЗ
    |   РегистрСведений.ПервоначальныеСведенияОСБухгалтерскийУчет.СрезПоследних КАК СрезПоследних
    |ГДЕ
    |   СрезПоследних.ИнвентарныйНомер <> """"";

Выборка = Запрос.Выполнить().Выбрать();

// 2. Формируем карту сопоставления нормализованных номеров
КартаОС = Новый Соответствие;
КартаДублей = Новый Соответствие;

Пока Выборка.Следующий() Цикл
    // Удаляем лидирующие нули штатной функцией БСП
    НормализованныйНомер = ПрефиксацияОбъектовКлиентСервер.УдалитьЛидирующиеНули(СокрЛП(Выборка.ИнвентарныйНомер));
    
    Если КартаОС[НормализованныйНомер] = Неопределено Тогда
        КартаОС.Вставить(НормализованныйНомер, Выборка.ОсновноеСредство);
    Иначе
        // Фиксируем коллизию номеров разной разрядности
        КартаДублей.Вставить(НормализованныйНомер, Истина);
    КонецЕсли;
КонецЦикла;

// 3. Быстрый поиск при обходе строк из Excel
НормализованныйНомерExcel = ПрефиксацияОбъектовКлиентСервер.УдалитьЛидирующиеНули(СокрЛП(Строка(НомерИзЭксель)));

Если КартаДублей[НормализованныйНомерExcel] = Истина Тогда
    Сообщить("Обнаружено неоднозначное соответствие для номера: " + НормализованныйНомерExcel);
Иначе
    НайденноеОС = КартаОС[НормализованныйНомерExcel];
    Если ЗначениеЗаполнено(НайденноеОС) Тогда
        // Основное средство успешно определено
    КонецЕсли;
КонецЕсли;

Способ 3. Пакетная загрузка через временную таблицу

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

Разберем по шагам:

  1. Создаем объект ТаблицаЗначений с колонками НомерСтрокиФайла, ИсходныйНомер, ОчищенныйНомер и ФорматированныйНомер (дополненный нулями до стандартной длины через СтроковыеФункцииКлиентСервер.ДополнитьСтроку).
  2. Заполняем таблицу данными из Excel.
  3. Передаем таблицу в единый пакетный запрос, строим временную таблицу и выполняем левое соединение с регистром сведений по очищенному и форматированному вариантам.

Рекомендации по предотвращению ошибок

При реализации алгоритмов сопоставления учитывайте следующие правила:

  1. Контролируйте дубликаты: Если в базе присутствуют объекты с номерами 01398 и 001398, удаление лидирующих нулей сведет оба номера к значению 1398. Алгоритм должен фиксировать подобные коллизии и требовать уточнения у пользователя, а не подставлять случайный элемент.
  2. Очищайте неразрывные пробелы: При чтении текстовых ячеек из Excel используйте замену неразрывных пробелов (Символы.НПП) на пустую строку, так как визуально пробел может быть незаметен, но помешает точному равенству строк.
  3. Используйте срез последних: Поскольку регистр ПервоначальныеСведенияОСБухгалтерскийУчет является периодическим, обращение к нему без виртуальной таблицы СрезПоследних может вернуть устаревшие записи по выбывшим или перемещенным объектам.
← На главную