При реализации механизмов загрузки данных из внешних источников (Excel, CSV, JSON) одной из самых приоритетных задач является контроль уникальности. Разработчики часто сталкиваются с ситуацией, когда, несмотря на наличие программных проверок, в справочнике Номенклатура все равно появляются дублирующиеся записи. Рассмотрим подробно, почему стандартные алгоритмы поиска могут давать сбой и как реализовать надежную проверку по нескольким полям, таким как Артикул и Наименование.
Проанализируем типичный запрос, который часто используют для предварительной выборки существующих данных из базы. В исходной задаче автор использовал условие ГДЕ Артикул В(&МассивАртикулов) И Наименование В(&МассивНаименований). Выясним причину, по которой это условие работает некорректно для поиска дублей.
Использование оператора И (AND) заставляет систему искать только те элементы, у которых одновременно совпадает и артикул, и наименование из переданных списков. Однако в реальности дублем может считаться позиция, у которой совпадает только артикул (но отличается наименование) или только наименование (но отличается артикул). Если в базе уже есть товар с нужным артикулом, но другим названием, запрос с оператором И его просто «не увидит», и программа создаст новую запись.
Для корректной проверки заменим логику на оператор ИЛИ (OR):
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Артикул КАК Артикул,
| Номенклатура.Наименование КАК Наименование
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| (Номенклатура.Артикул В (&МассивАртикулов)
| ИЛИ Номенклатура.Наименование В (&МассивНаименований))";
Такой подход позволит выгрузить из базы все потенциально конфликтующие записи.
После получения данных из запроса мы обычно помещаем их в массивы для быстрого поиска внутри цикла обработки файла. Рассмотрим, на что важно обратить внимание при использовании метода Массив.Найти().
Метод Найти() возвращает индекс найденного элемента (число от 0 и выше) или значение Неопределено, если совпадений нет. Распространенная ошибка заключается в неправильной интерпретации результата 0. В языке 1С условие Если Индекс Тогда будет воспринято как Ложь, если индекс равен 0 (первый элемент массива). Поэтому проверку всегда нужно делать явной:
НайденныйАртикул = ИтоговыйМассивАртикулов.Найти(Строка.Артикул);
Если НайденныйАртикул <> Неопределено Тогда
// Это дубль, нужно пропустить или обновить
Продолжить;
КонецЕсли;
Также важно помнить, что поиск в массиве по умолчанию чувствителен к регистру. Если в справочнике артикул записан как "abc-123", а в файле — "ABC-123", метод Найти() вернет Неопределено. Чтобы избежать этой проблемы, рекомендуется приводить строки к одному регистру с помощью функции ВРег() или НРег().
Линейный поиск в массиве (метод Найти()) при больших объемах данных работает медленно, так как системе приходится перебирать каждый элемент. Если в файле загрузки тысячи строк, время обработки будет расти в геометрической прогрессии. Посмотрим на более эффективный инструмент — объект Соответствие (Map).
Поиск в Соответствии осуществляется по хеш-таблице, что обеспечивает практически мгновенный результат вне зависимости от количества элементов. Перепишем наш алгоритм с использованием этой структуры:
// Создаем соответствия для быстрой проверки
СуществующиеАртикулы = Новый Соответствие;
СуществующиеНаименования = Новый Соответствие;
Для Каждого Стр Из ИтоговаяТаблицаЗапроса Цикл
СуществующиеАртикулы.Вставить(СократЛП(Стр.Артикул), Истина);
СуществующиеНаименования.Вставить(СократЛП(Стр.Наименование), Истина);
КонецЦикла;
// В цикле загрузки проверка будет выглядеть так:
Для Каждого СтрокаДанных Из Объект.ДанныеФайла Цикл
ТекущийАртикул = СократЛП(СтрокаДанных.Артикул);
ТекущееНаименование = СократЛП(СтрокаДанных.Наименование);
Если СуществующиеАртикулы[ТекущийАртикул] <> Неопределено Тогда
Сообщить("Пропуск: найден дубль по артикулу " + ТекущийАртикул);
Продолжить;
КонецЕсли;
// Аналогично для наименования...
КонецЦикла;
Выясним еще одну скрытую причину появления дублей — невидимые символы. При чтении данных из Excel в строках часто остаются лишние пробелы в начале или конце. Для 1С строки " 123" и "123 " — это разные значения.
Обязательно используйте функцию СократЛП() для всех строковых реквизитов, участвующих в проверке уникальности. Это простое правило предотвращает до 90% ошибок дублирования данных.
Если мы загружаем файл, в котором сами данные могут дублироваться, недостаточно просто проверить базу перед началом цикла. Нужно обновлять наши проверочные структуры (массивы или соответствия) сразу после создания нового элемента справочника. Рассмотрим правильную последовательность действий:
Соответствие.СократЛП).Соответствии артикула.Соответствии наименования.СправочникОбъект.Номенклатура.Соответствие, чтобы следующая строка файла с таким же товаром была распознана как дубль.Для опытных разработчиков наиболее надежным методом является использование временных таблиц прямо в запросе. Вместо того чтобы передавать массивы в условие В (&Массив), мы можем загрузить всю таблицу из файла в запрос, поместить ее во временную таблицу и выполнить Левое Соединение со справочником Номенклатура по артикулу и наименованию. Это позволит одним запросом получить список всех строк, которые уже есть в базе, и тех, которые являются новыми.
Этот метод исключает ошибки, связанные с регистром (если SQL-база настроена как регистронезависимая) и значительно ускоряет обработку за счет оптимизации на уровне СУБД.
Подводя итог, отметим: корректная загрузка без дублей требует внимания к деталям — от использования ИЛИ в запросах до очистки строк от пробелов и выбора правильных объектов для поиска в памяти (Соответствие вместо Массив).