Как правильно загрузить номенклатуру из Excel в 1С:Управление торговлей 10.3, чтобы избежать дублей и ошибок поиска?

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

Загрузка данных из внешних файлов (Excel, CSV, XML) — это одна из самых частых задач, с которыми сталкивается разработчик 1С. Однако начинающие программисты часто совершают ошибки в логике поиска существующих объектов, что приводит к появлению «мусора» в базе данных или пропуску важных позиций. Рассмотрим типичную проблему: при загрузке товаров со схожими названиями (например, «Телевизор» и «Телевизор Samsung») программа ошибочно считает их одним и тем же объектом. Проанализируем причины этой ситуации и разберем правильные способы реализации поиска и создания номенклатуры.

Причина проблемы: коварство оператора ПОДОБНО

В исходном коде автора для проверки наличия товара в базе использовался следующий запрос:


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

Разберем, почему такая конструкция работает некорректно для задачи точного поиска. Оператор ПОДОБНО (LIKE в SQL) предназначен для поиска по маске. Использование спецсимволов % (процент) означает, что внутри названия может быть любая последовательность символов.

Рассмотрим пример: в файле Excel у нас есть строка «Телевизор». В базе уже существует товар «Телевизор Samsung». Когда выполняется запрос с условием ПОДОБНО %Телевизор%, система находит «Телевизор Samsung», так как это наименование содержит искомое слово. В результате логика программы Если НЕ Выборка.Следующий() Тогда срабатывает так, будто товар уже есть в базе, и новый элемент «Телевизор» не создается.

Для решения этой проблемы необходимо использовать оператор строгого равенства = и убрать лишние символы процентов. Это гарантирует, что система найдет только тот товар, название которого символ в символ совпадает с данными из Excel.

Исправление логики поиска в запросе

Оптимальный вариант запроса для проверки существования номенклатуры выглядит следующим образом:


ПроверитьНоменклатуры = СокрЛП(ExcelПриложение.Cells(Строка, НоменклатураКол).Value);

Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ ССЫЛКА
    |ИЗ Справочник.Номенклатура
    |ГДЕ Наименование = &Наименование";
Запрос.УстановитьПараметр("Наименование", ПроверитьНоменклатуры);

РезультатЗапроса = Запрос.Выполнить();
Если РезультатЗапроса.Пустой() Тогда
    // Здесь пишем код создания новой номенклатуры
    НовыйЭлемент = Справочники.Номенклатура.СоздатьЭлемент();
    // ... заполнение реквизитов
    НовыйЭлемент.Записать();
    ТоварСсылка = НовыйЭлемент.Ссылка;
Иначе
    Выборка = РезультатЗапроса.Выбрать();
    Выборка.Следующий();
    ТоварСсылка = Выборка.Ссылка;
КонецЕсли;

Обратите внимание, что мы используем функцию СокрЛП(). Это критически важно, так как лишние пробелы в начале или конце строки из Excel (которые часто не видны глазу) сделают строки «Телевизор » и «Телевизор» разными для базы данных.

Нюансы метода НайтиПоНаименованию

В тексте обработки автора также встречается метод НайтиПоНаименованию(). У этого метода есть важный второй параметр — Истина (ПоискПоПолномуСовпадению). Если его не указать или установить в Ложь, 1С может вернуть первый попавшийся элемент, начинающийся с искомой строки.

Проанализируем правильный вызов метода:

СсылкаНаТовар = Справочники.Номенклатура.НайтиПоНаименованию(НаименованиеИзФайла, Истина);

Параметр Истина гарантирует, что поиск будет вестись по полному совпадению всей строки, а не по начальным символам.

Оптимизация: уходим от запросов в цикле

Рассмотрим ситуацию с точки зрения производительности. Выполнение запроса внутри цикла Для Строка = 2 По ExcelПоследняяСтрока — это серьезная архитектурная ошибка. Если в файле 5000 строк, программа сделает 5000 обращений к базе данных, что крайне медленно.

Выясним, как сделать загрузку быстрее. Правильный алгоритм действий должен быть таким:

  1. Прочитать все данные из Excel в таблицу значений (ТЗ) или массив.
  2. Собрать все уникальные наименования в один массив.
  3. Одним запросом найти все существующие элементы в базе данных.
  4. Сравнить список из файла со списком из базы и создать только отсутствующие позиции.

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


// 1. Читаем Excel в ТаблицуЗначений "ДанныеФайла"
// ... (код загрузки в ТЗ)

// 2. Получаем массив уникальных наименований
МассивНаименований = ДанныеФайла.ВыгрузитьКолонку("Наименование");
ОбщегоНазначения.УдалитьПовторяющиесяЭлементыМассива(МассивНаименований);

// 3. Ищем существующие в базе товары одним запросом
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ Наименование, Ссылка
    |ИЗ Справочник.Номенклатура
    |ГДЕ Наименование В (&МассивНаименований)";
Запрос.УстановитьПараметр("МассивНаименований", МассивНаименований);

// Сохраняем результат в Соответствие для быстрого поиска в памяти
НайденныеТовары = Новый Соответствие;
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
    НайденныеТовары.Вставить(Выборка.Наименование, Выборка.Ссылка);
КонецЦикла;

// 4. Основной цикл создания/обработки
Для Каждого СтрДанных Из ДанныеФайла Цикл
    ТоварСсылка = НайденныеТовары.Получить(СтрДанных.Наименование);
    
    Если ТоварСсылка = Неопределено Тогда
        // Создаем новый элемент, так как в базе его нет
        // После записи добавляем его в Соответствие, чтобы не создать дубль, 
        // если в Excel товар встретится повторно
        // ...
    КонецЕсли;
КонецЦикла;

Особенности создания номенклатуры в УТ 10.3

При работе с конфигурацией «Управление торговлей 10.3» (на обычных формах) важно помнить, что Справочник.Номенклатура имеет ряд специфических особенностей. Простого заполнения наименования недостаточно для полноценного учета.

Разберем по шагам, что нужно заполнить обязательно:

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


НовыйТовар = Справочники.Номенклатура.СоздатьЭлемент();
НовыйТовар.Наименование = "Телевизор";
НовыйТовар.ВидНоменклатуры = Справочники.ВидыНоменклатуры.НайтиПоНаименованию("Товар");
НовыйТовар.БазоваяЕдиницаИзмерения = Справочники.КлассификаторЕдиницИзмерения.НайтиПоКоду("796"); // Штуки
НовыйТовар.Записать(); // Сначала записываем, чтобы получить ссылку

// Теперь создаем единицу хранения остатков
НоваяЕдиница = Справочники.ЕдиницыИзмерения.СоздатьЭлемент();
НоваяЕдиница.Владелец = НовыйТовар.Ссылка;
НоваяЕдиница.Наименование = "шт";
НоваяЕдиница.ЕдиницаПоКлассификатору = НовыйТовар.БазоваяЕдиницаИзмерения;
НоваяЕдиница.Коэффициент = 1;
НоваяЕдиница.Записать();

// Указываем единицу в карточке товара
НовыйТоварОбъект = НовыйТовар.Ссылка.ПолучитьОбъект();
НовыйТоварОбъект.ЕдиницаХраненияОстатков = НоваяЕдиница.Ссылка;
НовыйТоварОбъект.Записать();

Завершение работы с Excel

Проанализируем техническую сторону работы с COM-объектом. Программисты часто забывают корректно закрывать процесс Excel, что приводит к «зависанию» памяти на сервере или компьютере пользователя.

Всегда используйте блок Попытка...Исключение и в блоке завершения или после цикла обязательно вызывайте ExcelПриложение.Quit(). Также рекомендуется обнулять переменную: ExcelПриложение = Неопределено;, чтобы сборщик мусора 1С быстрее освободил ресурсы. Для повышения надежности можно использовать чтение через ADO или сохранение файла в формат CSV/XML, что работает значительно быстрее и стабильнее, чем через COM.

Резюме: Чтобы загрузка работала корректно, используйте строгое сравнение в запросах (= вместо ПОДОБНО), всегда применяйте СокрЛП(), не забывайте про обязательные реквизиты в УТ 10.3 и старайтесь избегать выполнения запросов внутри циклов для обеспечения высокой скорости работы программы.

← На главную