Как сопоставить и объединить несколько таблиц значений по ключевому полю в 1С?

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

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

Метод 1: Использование запроса (рекомендуемый подход)

Использование механизма запросов в 1С является наиболее правильным и производительным методом для объединения таблиц. Этот подход позволяет платформе самостоятельно оптимизировать процесс сопоставления строк. Основная идея заключается в том, чтобы передать наши таблицы значений в запрос как параметры, поместить их во временные таблицы и выполнить соединение.

Разберем по шагам логику реализации через запрос:

  1. Подготовим таблицы значений, обязательно назначив им типы колонок. Без явного указания типов (через ОписаниеТипов) запрос не сможет корректно обработать данные.
  2. Передадим таблицы в качестве параметров объекта Запрос.
  3. В тексте запроса используем конструкцию ПОМЕСТИТЬ для каждой исходной таблицы.
  4. Выполним ЛЕВОЕ СОЕДИНЕНИЕ (Left Join) основной (эталонной) таблицы с остальными по полю VIN.
  5. Используем функцию ЕСТЬ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).

Метод 2: Программный перебор с использованием метода Найти()

Если по каким-то причинам использование запроса невозможно (например, данные слишком динамичны или их объем невелик), можно применить классический цикл. Выясним причину, по которой этот метод считается менее оптимальным: при каждом поиске методом Найти() платформа сканирует таблицу, что при больших объемах данных может привести к существенным задержкам.

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


// Индексация для ускорения поиска
Таблица2.Индексы.Добавить("VIN");
Таблица3.Индексы.Добавить("VIN");
Таблица4.Индексы.Добавить("VIN");

// Проход по эталонной таблице
Для Каждого СтрокаЭталон Из Таблица1 Цикл
    
    НоваяСтрока = СводнаяТЗ.Добавить();
    ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаЭталон);
    
    // Ищем соответствия в остальных таблицах
    НайденнаяСтрока2 = Таблица2.Найти(СтрокаЭталон.VIN, "VIN");
    Если НайденнаяСтрока2 <> Неопределено Тогда
        НоваяСтрока.РазрешеннаяМасса = НайденнаяСтрока2.РазрешеннаяМасса;
        НоваяСтрока.МодельныйГод = НайденнаяСтрока2.МодельныйГод;
    КонецЕсли;
    
    НайденнаяСтрока3 = Таблица3.Найти(СтрокаЭталон.VIN, "VIN");
    Если НайденнаяСтрока3 <> Неопределено Тогда
        НоваяСтрока.ВариантСборки = НайденнаяСтрока3.ВариантСборки;
    КонецЕсли;
    
    // И так далее для всех таблиц
КонецЦикла;

Метод 3: Использование объекта «Соответствие» (Map) для высокой производительности

Для максимально быстрого сопоставления «в памяти» без использования запросов лучше всего подходит объект Соответствие. Поиск в нем происходит по хэш-таблице, что значительно быстрее поиска в проиндексированной таблице значений.

Посмотрим на алгоритм:

  1. Создадим Соответствие для каждой дополнительной таблицы.
  2. Обойдем каждую таблицу один раз, записывая в соответствие VIN (ключ) и саму строку или структуру с данными (значение).
  3. В основном цикле по эталонной таблице будем получать данные из соответствий мгновенно по ключу.

// Подготовка данных
КартаДанных2 = Новый Соответствие;
Для Каждого Стр Из Таблица2 Цикл
    КартаДанных2.Вставить(Стр.VIN, Стр);
КонецЦикла;

// В основном цикле
СтрокаТ2 = КартаДанных2.Получить(СтрокаЭталон.VIN);
Если СтрокаТ2 <> Неопределено Тогда
    НоваяСтрока.Параметр = СтрокаТ2.Параметр;
КонецЕсли;

Важные практические рекомендации по работе с VIN

Поскольку сопоставление идет по строковому полю (VIN-код), проанализируем ситуацию с качеством данных. Разные источники могут предоставлять VIN в разном регистре или с лишними пробелами. Чтобы сопоставление не «сломалось», придерживайтесь следующих правил:

Подводя итог, можно сказать: для большинства задач в 1С 8.3 оптимальным выбором будет запрос с временными таблицами. Это чистый, легко читаемый и надежный код, который корректно обрабатывает типы данных и эффективно связывает большие объемы информации.

← На главную