Часто перед разработчиком стоит задача загрузить данные из внешнего источника (например, из файла Excel) и сопоставить их с уже существующими элементами в справочниках 1С. На первый взгляд задача кажется простой: поместить данные во временную таблицу и соединить её со справочником. Однако на практике программисты часто сталкиваются с тем, что результат запроса оказывается пустым или, наоборот, избыточным. Разберем пошагово, как правильно реализовать этот механизм, каких ошибок стоит избегать и как оптимизировать процесс.
Рассмотрим стандартную ситуацию: у нас есть таблица значений, полученная из файла, которую мы передаем в запрос. Основная ошибка, которую совершают новички, заключается в попытке сравнить несравнимое. Проанализируем типичный фрагмент кода:
|ВЫБРАТЬ
| ВТ_ТЧ_Норматив.Товары КАК Товары,
| Товары.Ссылка КАК Ссылка
|ИЗ
| Справочник.Товарлар КАК Товарлар
|ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ТЧ_Норматив КАК ВТ_ТЧ_Норматив
| ПО ВТ_ТЧ_Норматив.Товары = Товарлар.Ссылка
В этом примере кроется сразу две фундаментальные проблемы. Во-первых, если в поле ВТ_ТЧ_Норматив.Товары загружена строка из файла (наименование товара), то сравнение Строка = Ссылка всегда будет давать Ложь. Система 1С — это строго типизированная среда, и разные типы данных никогда не будут равны друг другу. Во-вторых, выбор ЛЕВОГО СОЕДИНЕНИЯ от справочника к временной таблице приведет к тому, что в результат попадут все элементы справочника, а данные из файла подтянутся только там, где нашлось совпадение (которого не будет из-за типов).
Прежде чем передавать таблицу в запрос, мы должны убедиться, что данные в ней «чистые». Рассмотрим, как правильно типизировать колонки. Если мы создаем таблицу значений программно, необходимо использовать ОписаниеТипов. Это критически важно для строковых полей, так как строки неограниченной длины нельзя использовать в условиях соединения запроса.
Разберем пример правильной подготовки таблицы:
ТЗ_Данные = Новый ТаблицаЗначений;
МассивТипаСтрока = Новый Массив;
МассивТипаСтрока.Добавить(Тип("Строка"));
ОписаниеТипаСтрока = Новый ОписаниеТипов(МассивТипаСтрока, , Новый КвалификаторыСтроки(150));
ТЗ_Данные.Колонки.Добавить("ТоварНаименование", ОписаниеТипаСтрока);
ТЗ_Данные.Колонки.Добавить("Норматив", Новый ОписаниеТипов("Число"));
// Заполнение данными из файла...
Для Каждого СтрокаФайла Из ДанныеФайла Цикл
НоваяСтрока = ТЗ_Данные.Добавить();
// Обязательно используем СокрЛП для удаления невидимых пробелов
НоваяСтрока.ТоварНаименование = СокрЛП(СтрокаФайла.Наименование);
НоваяСтрока.Норматив = СтрокаФайла.Значение;
КонецЦикла;
Важный нюанс: данные из Excel часто содержат «неразрывные пробелы» (символ с кодом 160). Визуально они не отличаются от обычных, но для запроса 1С это разные символы. Перед загрузкой рекомендуется заменять их на обычные пробелы с помощью функции СтрЗаменить(Текст, Символ(160), " ").
Выясним, какое соединение лучше использовать для задачи сопоставления. Если наша цель — вывести только те товары, которые есть в файле, и найти для них ссылки в базе, у нас есть два варианта:
Ссылка будет содержать NULL. Это полезно для формирования протокола ошибок («Товар не найден»).Посмотрим на исправленный текст запроса:
ВЫБРАТЬ
ТЧ.ТоварНаименование КАК ИмяИзФайла,
ТЧ.Норматив КАК Норматив
ПОМЕСТИТЬ ВТ_ДанныеФайла
ИЗ
&ТЗ_Данные КАК ТЧ
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_ДанныеФайла.ИмяИзФайла,
ВТ_ДанныеФайла.Норматив,
СпрТовары.Ссылка КАК СсылкаНаТовар
ИЗ
ВТ_ДанныеФайла КАК ВТ_ДанныеФайла
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Товары КАК СпрТовары
ПО ВТ_ДанныеФайла.ИмяИзФайла = СпрТовары.Наименование
Если в вашем файле или справочнике тысячи записей, запрос может начать «тормозить». Проанализируем ситуацию: системе приходится для каждой строки файла перебирать весь справочник. Чтобы ускорить процесс, необходимо индексировать временную таблицу по полю, по которому происходит сопоставление.
Для этого в тексте запроса после описания временной таблицы добавим команду индексации:
ПОМЕСТИТЬ ВТ_ДанныеФайла
ИЗ
&ТЗ_Данные КАК ТЧ
ИНДЕКСИРОВАТЬ ПО
ТоварНаименование
Сопоставление по наименованию — самый ненадежный способ. Лишняя точка, кавычка или опечатка приведут к тому, что товар не будет найден. Рассмотрим более надежные поля для связи:
ШтрихкодыНоменклатуры.Если сопоставление все же идет по наименованию, но данные в файле могут быть неточными, иногда применяют поиск по части строки. Разберем пример с использованием функции ПОДСТРОКА, хотя это и снижает производительность:
ПО ПОДСТРОКА(ВТ_ДанныеФайла.ИмяИзФайла, 1, 20) = ПОДСТРОКА(СпрТовары.Наименование, 1, 20)
После выполнения запроса мы получаем выборку. Важно помнить, что если в справочнике 1С есть два товара с одинаковым наименованием, то при левом соединении строка из вашего файла продублируется в результате запроса. Проанализируем, как этого избежать в коде обработки:
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
Если Выборка.СсылкаНаТовар = NULL Тогда
Сообщить("Товар не найден в базе: " + Выборка.ИмяИзФайла);
Продолжить;
КонецЕсли;
// Дальнейшая логика обработки...
КонецЦикла;
Для гарантированного исключения дублей со стороны 1С в самом запросе можно использовать конструкцию ВЫБРАТЬ РАЗЛИЧНЫЕ или сгруппировать результат по полям файла, выбирая МАКСИМУМ(Ссылка).
Мы рассмотрели процесс сопоставления данных и выяснили, что ключ к успеху кроется в трех вещах: строгой типизации колонок таблицы значений, очистке строк от лишних пробелов и правильном выборе направления соединения в запросе (от данных файла к базе 1С). Соблюдение этих правил позволит вам создавать надежные механизмы загрузки данных, устойчивые к ошибкам пользователей и особенностям внешних форматов.