В процессе разработки на платформе 1С часто возникает задача консолидации данных из разных источников. Представим ситуацию: у нас есть четыре таблицы значений (ТЗ), в каждой из которых содержатся специфические сведения об автомобилях. Общим идентификатором для всех таблиц выступает VIN-код. Наша цель — собрать «сводную» пятую таблицу, в которой по каждому VIN-коду будут сопоставлены данные изо всех четырех источников. Рассмотрим детально, как это реализовать наиболее эффективными способами.
Использование механизма запросов в 1С является наиболее правильным и производительным методом для объединения таблиц. Этот подход позволяет платформе самостоятельно оптимизировать процесс сопоставления строк. Основная идея заключается в том, чтобы передать наши таблицы значений в запрос как параметры, поместить их во временные таблицы и выполнить соединение.
Разберем по шагам логику реализации через запрос:
ОписаниеТипов) запрос не сможет корректно обработать данные.Запрос.ПОМЕСТИТЬ для каждой исходной таблицы.ЛЕВОЕ СОЕДИНЕНИЕ (Left Join) основной (эталонной) таблицы с остальными по полю VIN.ЕСТЬNULL, чтобы обработать ситуации, когда в дополнительных таблицах отсутствуют данные по конкретному VIN.Проанализируем пример кода, реализующий этот алгоритм:
// 1. Подготовка структуры (типизация колонок)
ОписаниеСтрока = Новый ОписаниеТипов("Строка",,,, Новый КвалификаторыСтроки(17));
ОписаниеЧисло = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2));
ТЗ1 = Новый ТаблицаЗначений;
ТЗ1.Колонки.Добавить("VIN", ОписаниеСтрока);
ТЗ1.Колонки.Добавить("МаркаМодель", ОписаниеСтрока);
// (Аналогично создаются ТЗ2, ТЗ3, ТЗ4 с их уникальными колонками)
// 2. Формирование запроса
ТекстЗапроса =
"ВЫБРАТЬ * ПОМЕСТИТЬ втТЗ1 ИЗ &ТЗ1 КАК Т1;
|////////////////////////////////////////////////////////////////
|ВЫБРАТЬ * ПОМЕСТИТЬ втТЗ2 ИЗ &ТЗ2 КАК Т2;
|////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| втТЗ1.VIN КАК VIN,
| втТЗ1.МаркаМодель КАК МаркаМодель,
| ЕСТЬNULL(втТЗ2.РазрешеннаяМасса, 0) КАК РазрешеннаяМасса,
| ЕСТЬNULL(втТЗ2.МодельныйГод, """") КАК МодельныйГод
|ИЗ
| втТЗ1 КАК втТЗ1
| ЛЕВОЕ СОЕДИНЕНИЕ втТЗ2 КАК втТЗ2 ПО втТЗ1.VIN = втТЗ2.VIN";
Запрос = Новый Запрос(ТекстЗапроса);
Запрос.УстановитьПараметр("ТЗ1", ТЗ1);
Запрос.УстановитьПараметр("ТЗ2", ТЗ2);
// Выгрузка результата в сводную таблицу
СводнаяТаблица = Запрос.Выполнить().Выгрузить();
Важный нюанс: Если в эталонной таблице (ТЗ1) могут отсутствовать некоторые VIN, которые есть в других таблицах, используйте ПОЛНОЕ СОЕДИНЕНИЕ. В этом случае результирующее поле VIN нужно выбирать так: ЕСТЬNULL(втТЗ1.VIN, втТЗ2.VIN).
Если по каким-то причинам использование запроса невозможно (например, данные слишком динамичны или их объем невелик), можно применить классический цикл. Выясним причину, по которой этот метод считается менее оптимальным: при каждом поиске методом Найти() платформа сканирует таблицу, что при больших объемах данных может привести к существенным задержкам.
Рассмотрим, как оптимизировать этот процесс. Перед началом цикла крайне важно проиндексировать колонку VIN в тех таблицах, где будет осуществляться поиск. Рассмотрим пример кода:
// Индексация для ускорения поиска
Таблица2.Индексы.Добавить("VIN");
Таблица3.Индексы.Добавить("VIN");
Таблица4.Индексы.Добавить("VIN");
// Проход по эталонной таблице
Для Каждого СтрокаЭталон Из Таблица1 Цикл
НоваяСтрока = СводнаяТЗ.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаЭталон);
// Ищем соответствия в остальных таблицах
НайденнаяСтрока2 = Таблица2.Найти(СтрокаЭталон.VIN, "VIN");
Если НайденнаяСтрока2 <> Неопределено Тогда
НоваяСтрока.РазрешеннаяМасса = НайденнаяСтрока2.РазрешеннаяМасса;
НоваяСтрока.МодельныйГод = НайденнаяСтрока2.МодельныйГод;
КонецЕсли;
НайденнаяСтрока3 = Таблица3.Найти(СтрокаЭталон.VIN, "VIN");
Если НайденнаяСтрока3 <> Неопределено Тогда
НоваяСтрока.ВариантСборки = НайденнаяСтрока3.ВариантСборки;
КонецЕсли;
// И так далее для всех таблиц
КонецЦикла;
Для максимально быстрого сопоставления «в памяти» без использования запросов лучше всего подходит объект Соответствие. Поиск в нем происходит по хэш-таблице, что значительно быстрее поиска в проиндексированной таблице значений.
Посмотрим на алгоритм:
Соответствие для каждой дополнительной таблицы.
// Подготовка данных
КартаДанных2 = Новый Соответствие;
Для Каждого Стр Из Таблица2 Цикл
КартаДанных2.Вставить(Стр.VIN, Стр);
КонецЦикла;
// В основном цикле
СтрокаТ2 = КартаДанных2.Получить(СтрокаЭталон.VIN);
Если СтрокаТ2 <> Неопределено Тогда
НоваяСтрока.Параметр = СтрокаТ2.Параметр;
КонецЕсли;
Поскольку сопоставление идет по строковому полю (VIN-код), проанализируем ситуацию с качеством данных. Разные источники могут предоставлять VIN в разном регистре или с лишними пробелами. Чтобы сопоставление не «сломалось», придерживайтесь следующих правил:
ВРег() перед поиском или помещением в запрос.СокрЛП(), чтобы исключить случайные пробелы по краям строки.Найти() вернет только первый результат. Если вам нужны все вхождения, используйте НайтиСтроки() (возвращает массив) или группировку в запросе.Подводя итог, можно сказать: для большинства задач в 1С 8.3 оптимальным выбором будет запрос с временными таблицами. Это чистый, легко читаемый и надежный код, который корректно обрабатывает типы данных и эффективно связывает большие объемы информации.