Как обновить артикулы номенклатуры из загруженного CSV-файла в 1С

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

При интеграции данных и пакетной обработке справочников часто возникает задача сопоставить элементы по старым реквизитам и записать новые значения. Разберем типичную проблему: из CSV-файла прочитана таблица соответствий, содержащая колонки со старыми и новыми артикулами, и требуется найти соответствующие позиции в справочнике Номенклатура и обновить их реквизит Артикул.

Анализ частых ошибок при реализации сопоставления

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

  1. Неверное получение значений из таблицы для передачи в запрос: вызов Таблица.Колонки.Найти(...) возвращает метаданные колонки (объект КолонкаТаблицыЗначений), а не сами значения строк. Чтобы получить массив значений колонки, необходимо использовать метод Таблица.ВыгрузитьКолонку("ИмяКолонки").
  2. Несоответствие имен колонок: если при чтении файла пробелы удалялись программно (например, функцией СтрЗаменить(ИмяКолонки, " ", "")), имя колонки "Старый код САЕ" превратилось в "СтарыйкодСАЕ". Попытка обращаться к колонке по старому наименованию с пробелами вернет Неопределено или вызовет ошибку.
  3. Разница в кодировках символов: буквы русского и латинского алфавитов «С», «А», «Е» пишутся одинаково, но имеют разные коды. Обязательно проверяйте правильность написания строковых идентификаторов.
  4. Лишние пробелы в значениях: текстовые поля из CSV часто содержат пробелы в начале или конце строки. Перед поиском или передачей в запрос строковые значения следует очищать методом СокрЛП().

Способ 1. Оптимальное пакетное обновление через временную таблицу

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

Разберем по шагам реализацию процедуры обработки:


Процедура КнопкаВыполнитьНажатие(Кнопка)
    
    // Подготовим таблицу для передачи в запрос
    ТаблицаСоответствий = Новый ТаблицаЗначений;
    ТаблицаСоответствий.Колонки.Добавить("СтарыйАртикул", Новый ОписаниеТипов("Строка",,,, Новый КвалификаторыСтроки(50)));
    ТаблицаСоответствий.Колонки.Добавить("НовыйАртикул", Новый ОписаниеТипов("Строка",,,, Новый КвалификаторыСтроки(50)));
    
    Для Каждого Стр Из Таблица Цикл
        // Проверяем заполненность колонок (используем точные имена колонок без пробелов)
        Если Не ПустаяСтрока(Стр.СтарыйкодСАЕ) И Не ПустаяСтрока(Стр.НовыйкодСАЕ) Тогда
            НоваяСтр = ТаблицаСоответствий.Добавить();
            НоваяСтр.СтарыйАртикул = СокрЛП(Стр.СтарыйкодСАЕ);
            НоваяСтр.НовыйАртикул  = СокрЛП(Стр.НовыйкодСАЕ);
        КонецЕсли;
    КонецЦикла;
    
    Если ТаблицаСоответствий.Количество() = 0 Тогда
        Сообщить("Нет данных для обработки.");
        Возврат;
    КонецЕсли;

    // Выполняем запрос с использованием временной таблицы
    Запрос = Новый Запрос;
    МенеджерВТ = Новый МенеджерВременныхТаблиц;
    Запрос.МенеджерВременныхТаблиц = МенеджерВТ;
    
    Запрос.Текст = 
    "ВЫБРАТЬ
    |    Таб.СтарыйАртикул КАК СтарыйАртикул,
    |    Таб.НовыйАртикул КАК НовыйАртикул
    |ПОМЕСТИТЬ ВТ_Соответствия
    |ИЗ
    |    &ТаблицаСоответствий КАК Таб
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ
    |    СпрНоменклатура.Ссылка КАК Ссылка,
    |    ВТ_Соответствия.НовыйАртикул КАК НовыйАртикул
    |ИЗ
    |    ВТ_Соответствия КАК ВТ_Соответствия
    |        ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК СпрНоменклатура
    |        ПО (ВТ_Соответствия.СтарыйАртикул = СпрНоменклатура.Артикул)";
    
    Запрос.УстановитьПараметр("ТаблицаСоответствий", ТаблицаСоответствий);
    
    РезультатЗапроса = Запрос.Выполнить();
    Выборка = РезультатЗапроса.Выбрать();
    
    Счетчик = 0;
    НачатьТранзакцию();
    
    Попытка
        Пока Выборка.Следующий() Цикл
            
            ОбъектНоменклатура = Выборка.Ссылка.ПолучитьОбъект();
            ОбъектНоменклатура.ОбменДанными.Загрузка = Истина; // Отключаем лишние обработчики при записи
            ОбъектНоменклатура.Артикул = Выборка.НовыйАртикул;
            ОбъектНоменклатура.Записать();
            
            Счетчик = Счетчик + 1;
            
            // Фиксируем транзакцию порциями для экономии памяти
            Если Счетчик % 500 = 0 Тогда
                ЗафиксироватьТранзакцию();
                НачатьТранзакцию();
            КонецЕсли;
            
        КонецЦикла;
        
        ЗафиксироватьТранзакцию();
        Сообщить("Успешно обновлено позиций: " + Строка(Счетчик));
        
    Исключение
        ОтменитьТранзакцию();
        Сообщить("Ошибка при обновлении данных: " + ОписаниеОшибки());
    КонецПопытки;
    
КонецПроцедуры

Способ 2. Построчный поиск и обновление через НайтиПоРеквизиту

Если объем данных невелик, можно применить прямой обход строк с использованием метода менеджера справочника Справочники.Номенклатура.НайтиПоРеквизиту(). Посмотрим на пример реализации:


Процедура ОбновитьАртикулыПострочно()
    
    Для Каждого Стр Из Таблица Цикл
        
        СтарыйАртикул = СокрЛП(Стр.СтарыйкодСАЕ);
        НовыйАртикул  = СокрЛП(Стр.НовыйкодСАЕ);
        
        Если ПустаяСтрока(СтарыйАртикул) Или ПустаяСтрока(НовыйАртикул) Тогда
            Продолжить;
        КонецЕсли;
        
        СсылкаНоменклатура = Справочники.Номенклатура.НайтиПоРеквизиту("Артикул", СтарыйАртикул);
        
        Если Не СсылкаНоменклатура.Пустая() Тогда
            Попытка
                Объект = СсылкаНоменклатура.ПолучитьОбъект();
                Объект.ОбменДанными.Загрузка = Истина;
                Объект.Артикул = НовыйАртикул;
                Объект.Записать();
            Исключение
                Сообщить("Не удалось записать номенклатуру """ + Строка(СсылкаНоменклатура) + """: " + ОписаниеОшибки());
            КонецПопытки;
        Иначе
            Сообщить("Номенклатура со старым артикулом не найдена: " + СтарыйАртикул);
        КонецЕсли;
        
    КонецЦикла;
    
КонецПроцедуры

Важные рекомендации при массовой перезаписи объектов

  1. Режим загрузки данных: установка свойства Объект.ОбменДанными.Загрузка = Истина отключает прикладные проверки в модуле объекта и модулях наборов записей, что ускоряет выполнение и предотвращает непредвиденные сбои на некритичных проверках.
  2. Управление транзакциями: выполнение записи большого числа объектов внутри явных транзакций порциями (по 500–1000 штук) существенно сокращает время дисковых операций и снижает нагрузку на СУБД.
  3. Неуникальные артикулы: обратите внимание, что метод НайтиПоРеквизиту находит только первый попавшийся элемент. Если в информационной базе могут присутствовать дублирующиеся старые артикулы, следует использовать Способ 1 (запрос через временную таблицу), который корректно выберет и обновит все найденные дубли.
← На главную