Как объединить две несвязанные таблицы в колонки в запросе или коде 1С?

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

В практике разработчика 1С часто возникает задача объединения двух наборов данных «горизонтально». Представьте ситуацию: у вас есть первая таблица с двумя записями и вторая таблица с тремя записями. Между ними нет логической связи (ключей), но вам необходимо получить единый результат, где данные из первой таблицы стоят в первой колонке, а данные из второй — во второй, при этом недостающие значения должны быть заполнены NULL. В этой статье мы подробно разберем, как реализовать такое объединение средствами языка запросов и программными методами 1С.

Метод 1: Имитация порядкового номера в запросе

Основная сложность в языке запросов 1С заключается в отсутствии стандартной функции ROW_NUMBER(), которая есть в классическом SQL. Поэтому, чтобы соединить две таблицы «по строкам», нам нужно сначала эти строки пронумеровать. Рассмотрим, как это сделать с помощью временных таблиц и левого соединения.

Проанализируем алгоритм решения этой задачи:

  1. Создадим первую временную таблицу с исходными данными.
  2. Создадим вторую временную таблицу.
  3. Для каждой таблицы выполним «самосоединение» по условию >=. Это позволит нам подсчитать количество записей, которые «меньше или равны» текущей, что и станет нашим порядковым номером.
  4. Выполним ПОЛНОЕ СОЕДИНЕНИЕ двух пронумерованных таблиц по полю номера.

Рассмотрим пример кода запроса:


// Подготовка первой таблицы
ВЫБРАТЬ "А1" КАК Поле1 ПОМЕСТИТЬ ВТ_1 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "А2";

////////////////////////////////////////////////////////////////
// Подготовка второй таблицы 
ВЫБРАТЬ "Б1" КАК Поле2 ПОМЕСТИТЬ ВТ_2 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "Б2" ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "Б3";

////////////////////////////////////////////////////////////////
// Нумерация первой таблицы
ВЫБРАТЬ
    КОЛИЧЕСТВО(ВТ_1_Доп.Поле1) КАК Номер,
    ВТ_1.Поле1 КАК Поле1
ПОМЕСТИТЬ ВТ_1_Номера
ИЗ
    ВТ_1 КАК ВТ_1
        ЛЕВОЕ СОЕДИНЕНИЕ ВТ_1 КАК ВТ_1_Доп
        ПО ВТ_1.Поле1 >= ВТ_1_Доп.Поле1
СГРУППИРОВАТЬ ПО
    ВТ_1.Поле1;

////////////////////////////////////////////////////////////////
// Нумерация второй таблицы
ВЫБРАТЬ
    КОЛИЧЕСТВО(ВТ_2_Доп.Поле2) КАК Номер,
    ВТ_2.Поле2 КАК Поле2
ПОМЕСТИТЬ ВТ_2_Номера
ИЗ
    ВТ_2 КАК ВТ_2
        ЛЕВОЕ СОЕДИНЕНИЕ ВТ_2 КАК ВТ_2_Доп
        ПО ВТ_2.Поле2 >= ВТ_2_Доп.Поле2
СГРУППИРОВАТЬ ПО
    ВТ_2.Поле2;

////////////////////////////////////////////////////////////////
// Финальное соединение
ВЫБРАТЬ
    ВТ_1_Номера.Поле1 КАК Поле1,
    ВТ_2_Номера.Поле2 КАК Поле2
ИЗ
    ВТ_1_Номера КАК ВТ_1_Номера
        ПОЛНОЕ СОЕДИНЕНИЕ ВТ_2_Номера КАК ВТ_2_Номера
        ПО ВТ_1_Номера.Номер = ВТ_2_Номера.Номер;

Важное замечание: Этот метод имеет квадратичную сложность O(n²). Если в ваших таблицах будет более тысячи строк, запрос может начать существенно «тормозить», так как для каждой строки выполняется поиск по всем остальным строкам. Также обратите внимание на условие ВТ_1.Поле1 >= ВТ_1_Доп.Поле1. Чтобы нумерация была корректной, поле, по которому идет сравнение, должно быть уникальным. Если значения могут дублироваться, используйте уникальные идентификаторы, такие как Ссылка.

Метод 2: Использование программной обработки Таблицы Значений

Если данные уже получены в коде 1С, гораздо эффективнее использовать методы объекта ТаблицаЗначений. Проанализируем способ использования метода ЗагрузитьКолонку. Этот метод позволяет вставить массив данных непосредственно в существующую колонку таблицы по индексам строк.

Разберем по шагам, как это реализовать:

  1. Определяем, в какой таблице больше строк. Это критически важно, так как метод ЗагрузитьКолонку не расширяет таблицу-приемник автоматически.
  2. Добавляем пустую колонку в таблицу с максимальным количеством строк.
  3. Выгружаем данные из колонки второй таблицы в массив.
  4. Загружаем этот массив в новую колонку первой таблицы.

Посмотрим на пример реализации:


// Создаем исходные таблицы
ТЗ1 = Новый ТаблицаЗначений;
ТЗ1.Колонки.Добавить("S1");
ТЗ1.Добавить().S1 = "s11";
ТЗ1.Добавить().S1 = "s12";

ТЗ2 = Новый ТаблицаЗначений;
ТЗ2.Колонки.Добавить("S2");
ТЗ2.Добавить().S2 = "s21";
ТЗ2.Добавить().S2 = "s22";
ТЗ2.Добавить().S2 = "s23";

// Выясним, какая таблица длиннее
ТаблицаРезультат = ?(ТЗ1.Количество() > ТЗ2.Количество(), ТЗ1, ТЗ2);
ТаблицаИсточник = ?(ТЗ1.Количество() > ТЗ2.Количество(), ТЗ2, ТЗ1);

// Добавляем колонку из источника в результат
ИмяКолонкиИсточника = ТаблицаИсточник.Колонки[0].Имя;
ТаблицаРезультат.Колонки.Добавить(ИмяКолонкиИсточника);

// Переносим данные через массив
МассивДанных = ТаблицаИсточник.ВыгрузитьКолонку(ИмяКолонкиИсточника);
ТаблицаРезультат.ЗагрузитьКолонку(МассивДанных, ИмяКолонкиИсточника);

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

Метод 3: Особенности соединения по условию ИСТИНА

Иногда начинающие разработчики пытаются использовать ПОЛНОЕ СОЕДИНЕНИЕ по условию ПО (ИСТИНА). Выясним причину, почему это плохая идея для данной задачи. Такое соединение называется Cross Join (декартово произведение). В результате вы получите не 3 строки (как в нашем примере), а 2 * 3 = 6 строк. Каждая запись первой таблицы соединится с каждой записью второй таблицы. Это полностью противоречит условию задачи, где требуется просто вывести данные параллельно друг другу.

Метод 4: Работа с временными таблицами через Менеджер

Если вам необходимо объединить данные программно (как в Методе 2), но затем снова использовать их в сложном запросе, мы рекомендуем использовать МенеджерВременныхТаблиц. Вы можете подготовить итоговую таблицу в коде, а затем передать ее обратно в запрос следующим образом:


МенеджерВТ = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;

// Помещаем подготовленную таблицу значений во временную таблицу запроса
Запрос.Текст = "ВЫБРАТЬ * ПОМЕСТИТЬ ИтоговаяТаблица ИЗ &ВнешняяТЗ КАК ВнешняяТЗ";
Запрос.УстановитьПараметр("ВнешняяТЗ", ТаблицаРезультат);
Запрос.Выполнить();

Это позволяет комбинировать гибкость программной обработки данных с мощностью механизмов запросов 1С.

Резюме и рекомендации

Выбор метода зависит от объема данных и места выполнения кода:

Мы рассмотрели основные способы «горизонтального» объединения таблиц. Помните, что платформа 1С предоставляет множество инструментов для манипуляции данными, и правильный выбор инструмента напрямую влияет на скорость работы вашей системы.

← На главную