При загрузке данных из внешних таблиц Excel часто возникает проблема несовпадения форматов строковых идентификаторов. Например, инвентарный номер в регистре сведений ПервоначальныеСведенияОСБухгалтерскийУчет может храниться как 00001398 или 00101398, тогда как из Excel считывается число 1398. При этом длина номеров в базе может быть разной, а прямое использование условий с ПОДОБНО (LIKE) либо запрещено требованиями к производительности, либо приводит к ложным срабатываниям.
Разберем причины этой проблемы, возможные подводные камни и несколько эффективных способов сопоставления данных на платформе 1С:Предприятие.
Проанализируем основные технические особенности и риски при работе с инвентарными номерами:
LTRIM с параметром или регулярных выражений). Нельзя прямо в запросе безопасно урезать только нули слева.00001098 превратится в 198, что нарушит уникальность и сопоставление.ИнвентарныйНомер в типовых регистрах сведений бухгалтерского учета ОС чаще всего является ресурсом, а не измерением. Выполнение запросов с неточным поиском в цикле для каждой строки файла Excel приведет к критическому замедлению загрузки.Рассмотрим вариант, когда необходимо найти конкретное основное средство по известному значению из Excel, сгенерировав все возможные варианты дополнения лидирующими нулями с учетом максимальной длины поля в метаданных.
Разберем по шагам алгоритм подготовки данных:
Метаданные.ГДЕ ИнвентарныйНомер В (&МассивПотенциальныхНомеров).Посмотрим на пример реализации данного алгоритма:
ДлинаНомераВРегистре = Метаданные.РегистрыСведений.ПервоначальныеСведенияОСБухгалтерскийУчет.Ресурсы.ИнвентарныйНомер.Тип.КвалификаторыСтроки.Длина;
МассивПотенциальныхНомеров = Новый Массив;
Если ТипЗнч(НомерИзЭксель) = Тип("Число") Тогда
СтрИнвентарныйНомер = Формат(НомерИзЭксель, "ЧГ=0");
Иначе
СтрИнвентарныйНомер = Прав(СокрЛП(НомерИзЭксель), ДлинаНомераВРегистре);
КонецЕсли;
МассивПотенциальныхНомеров.Добавить(СтрИнвентарныйНомер);
Пока СтрДлина(СтрИнвентарныйНомер) < ДлинаНомераВРегистре Цикл
СтрИнвентарныйНомер = "0" + СтрИнвентарныйНомер;
МассивПотенциальныхНомеров.Добавить(СтрИнвентарныйНомер);
КонецЦикла;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| СрезПоследних.ОсновноеСредство КАК ОсновноеСредство,
| СрезПоследних.ИнвентарныйНомер КАК ИнвентарныйНомер
|ИЗ
| РегистрСведений.ПервоначальныеСведенияОСБухгалтерскийУчет.СрезПоследних(, ИнвентарныйНомер В (&МассивПотенциальныхНомеров)) КАК СрезПоследних";
Запрос.УстановитьПараметр("МассивПотенциальныхНомеров", МассивПотенциальныхНомеров);
РезультатЗапроса = Запрос.Выполнить();
Если в файле Excel содержится большое количество строк, выполнять отдельные запросы для каждой позиции неэффективно. Оптимальным решением будет однократное чтение данных регистра в память с последующей нормализацией инвентарных номеров через быстрый поиск в объекте Соответствие.
Для корректного удаления только лидирующих нулей используем штатные функции Библиотеки стандартных подсистем (БСП): ПрефиксацияОбъектовКлиентСервер.УдалитьЛидирующиеНули или СтроковыеФункцииКлиентСервер.УдалитьСимволыСлева.
Рассмотрим пример реализации пакетного сопоставления:
// 1. Получаем все актуальные сведения об ОС единым запросом
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| СрезПоследних.ОсновноеСредство КАК ОсновноеСредство,
| СрезПоследних.ИнвентарныйНомер КАК ИнвентарныйНомер
|ИЗ
| РегистрСведений.ПервоначальныеСведенияОСБухгалтерскийУчет.СрезПоследних КАК СрезПоследних
|ГДЕ
| СрезПоследних.ИнвентарныйНомер <> """"";
Выборка = Запрос.Выполнить().Выбрать();
// 2. Формируем карту сопоставления нормализованных номеров
КартаОС = Новый Соответствие;
КартаДублей = Новый Соответствие;
Пока Выборка.Следующий() Цикл
// Удаляем лидирующие нули штатной функцией БСП
НормализованныйНомер = ПрефиксацияОбъектовКлиентСервер.УдалитьЛидирующиеНули(СокрЛП(Выборка.ИнвентарныйНомер));
Если КартаОС[НормализованныйНомер] = Неопределено Тогда
КартаОС.Вставить(НормализованныйНомер, Выборка.ОсновноеСредство);
Иначе
// Фиксируем коллизию номеров разной разрядности
КартаДублей.Вставить(НормализованныйНомер, Истина);
КонецЕсли;
КонецЦикла;
// 3. Быстрый поиск при обходе строк из Excel
НормализованныйНомерExcel = ПрефиксацияОбъектовКлиентСервер.УдалитьЛидирующиеНули(СокрЛП(Строка(НомерИзЭксель)));
Если КартаДублей[НормализованныйНомерExcel] = Истина Тогда
Сообщить("Обнаружено неоднозначное соответствие для номера: " + НормализованныйНомерExcel);
Иначе
НайденноеОС = КартаОС[НормализованныйНомерExcel];
Если ЗначениеЗаполнено(НайденноеОС) Тогда
// Основное средство успешно определено
КонецЕсли;
КонецЕсли;
Если сопоставление требуется выполнить непосредственно в запросе вместе с другими реквизитами документа (например, при сложной проверке счетов учета, подразделений или МОЛ), оптимально загрузить нормализованную таблицу Excel во временную таблицу.
Разберем по шагам:
ТаблицаЗначений с колонками НомерСтрокиФайла, ИсходныйНомер, ОчищенныйНомер и ФорматированныйНомер (дополненный нулями до стандартной длины через СтроковыеФункцииКлиентСервер.ДополнитьСтроку).При реализации алгоритмов сопоставления учитывайте следующие правила:
01398 и 001398, удаление лидирующих нулей сведет оба номера к значению 1398. Алгоритм должен фиксировать подобные коллизии и требовать уточнения у пользователя, а не подставлять случайный элемент.Символы.НПП) на пустую строку, так как визуально пробел может быть незаметен, но помешает точному равенству строк.ПервоначальныеСведенияОСБухгалтерскийУчет является периодическим, обращение к нему без виртуальной таблицы СрезПоследних может вернуть устаревшие записи по выбывшим или перемещенным объектам.