К статье
Практический материал

Разработка и Конфигурация · 12 мин

Как соединить две таблицы значений в 1С

Как объединить две таблицы значений в 1С: запрос с СОЕДИНИТЬ, запрос к таблицам через ВТ, программный перебор, свертка. Примеры кода, ошибки и проверка результата.

Таблица значений в 1С — универсальная структура для промежуточных расчётов, загрузки данных из файлов и подготовки отчётов. Задача соединить две такие таблицы возникает постоянно: сопоставить остатки из двух источников, объединить выгрузки, дополнить одну таблицу колонками из другой по ключу. Готового метода «СоединитьТаблицы» в языке нет, поэтому разработчик выбирает один из рабочих приёмов: запрос с помещением таблиц во временные, программный перебор с поиском по индексу либо простое добавление строк при совпадающей структуре.

Выбор способа зависит от трёх условий: есть ли у таблиц общий ключ для связи, совпадает ли структура колонок и насколько велики данные. Для таблиц в десятки тысяч строк перебор без индексации станет узким местом, а запрос к временным таблицам отработает заметно быстрее. Для пары сотен строк разница неощутима, и проще написать прямой цикл.

Ниже разобраны оба подхода с готовым кодом, типичные ошибки с типами колонок и способы проверить, что соединение выполнено корректно и без потери строк.

Определите тип соединения: склейка строк или объединение по ключу

Прежде чем писать код, ответьте на вопрос: что именно должно получиться на выходе. В практике встречаются две разные задачи, которые часто путают. Первая — вертикальная склейка: у обеих таблиц одинаковые колонки, и нужно просто добавить строки второй таблицы в конец первой. Вторая — горизонтальное соединение: таблицы связаны ключевым полем (номенклатура, контрагент, номер документа), и нужно подтянуть колонки одной таблицы к строкам другой.

Для склейки достаточно цикла, для соединения по ключу нужен аналог SQL JOIN. Внутри соединения по ключу тоже есть варианты: внутреннее соединение (только совпавшие строки), левое (все строки первой таблицы плюс совпадения из второй), полное внешнее (все строки обеих). От этого выбора зависит, не потеряете ли вы строки, у которых нет пары.

Маршрут решения

Как выбрать способ

Структура колонок совпадает, нужно просто объединить строкиЦикл Для Каждого с Добавить и ЗаполнитьЗначенияСвойств
Таблицы связаны ключом, объём больше нескольких тысяч строкЗапрос с помещением таблиц во временные и СОЕДИНЕНИЕ
Таблицы небольшие, нужна гибкая логика сопоставленияПеребор с НайтиСтроки и предварительным построением индекса
Нужны все строки обеих таблиц, включая несовпавшиеПОЛНОЕ СОЕДИНЕНИЕ в запросе либо два прохода перебором

Склейка таблиц с одинаковой структурой

Самый простой случай — обе таблицы имеют одинаковый набор колонок и типы, а задача сводится к объединению строк. Перебираете вторую таблицу и добавляете каждую строку в первую:

Для Каждого СтрокаТЗ Из Таблица2 Цикл

НоваяСтрока = Таблица1.Добавить();

ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаТЗ);

КонецЦикла;

Метод ЗаполнитьЗначенияСвойств переносит значения по совпадающим именам колонок, поэтому порядок колонок в таблицах может отличаться — важно только совпадение имён. Если каких-то колонок во второй таблице нет, соответствующие ячейки останутся пустыми, и это нужно учитывать при дальнейшей обработке.

После склейки часто требуется убрать дубли. Для этого используется метод Свернуть с указанием колонок группировки и, при необходимости, суммируемых колонок: Таблица1.Свернуть("Номенклатура, Склад", "Количество, Сумма"). Учтите, что свёртка необратимо изменяет таблицу — если исходные строки ещё понадобятся, сделайте копию через Таблица1.Скопировать() заранее.

Соединение по ключу через запрос к временным таблицам

Основной производительный способ — поместить обе таблицы значений во временные таблицы менеджера временных таблиц и выполнить обычный запрос с соединением. Это единственный вариант, где доступны все виды JOIN языка запросов 1С.

Запрос = Новый Запрос;

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

Запрос.Текст =

"ВЫБРАТЬ

| Т1.Номенклатура КАК Номенклатура,

| Т1.Количество КАК Количество

|ПОМЕСТИТЬ ВТ_Таб1

|ИЗ &Таб1 КАК Т1

|;

|ВЫБРАТЬ

| Т2.Номенклатура КАК Номенклатура,

| Т2.Цена КАК Цена

|ПОМЕСТИТЬ ВТ_Таб2

|ИЗ &Таб2 КАК Т2

|;

|ВЫБРАТЬ

| Т1.Номенклатура,

| Т1.Количество,

| ЕСТЬNULL(Т2.Цена, 0) КАК Цена

|ИЗ ВТ_Таб1 КАК Т1

| ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Таб2 КАК Т2

| ПО Т1.Номенклатура = Т2.Номенклатура";

Запрос.УстановитьПараметр("Таб1", Таблица1);

Запрос.УстановитьПараметр("Таб2", Таблица2);

Результат = Запрос.Выполнить().Выгрузить();

Обратите внимание на функцию ЕСТЬNULL: при левом соединении для строк без пары колонки второй таблицы содержат NULL. Если оставить NULL в числовой колонке, последующие расчёты и сравнения могут вести себя неожиданно — заменяйте NULL на значение по умолчанию сразу в запросе.

При передаче таблицы значений параметром запроса платформа накладывает ограничение: типы колонок должны быть однозначно определены. Если колонка имеет составной тип или не заполнена ни в одной строке, запрос может завершиться ошибкой. Надёжнее заранее объявить типы колонок через ОписаниеТипов при создании таблицы.

Программное соединение перебором с поиском

Когда запрос избыточен (небольшие таблицы, сложная логика сопоставления, работа в толстом клиенте без сервера), соединение делают перебором. Наивный вариант — для каждой строки первой таблицы вызывать Найти по второй:

Для Каждого СтрокаТ1 Из Таблица1 Цикл

СтрокаТ2 = Таблица2.Найти(СтрокаТ1.Номенклатура, "Номенклатура");

Если СтрокаТ2 <> Неопределено Тогда

СтрокаТ1.Цена = СтрокаТ2.Цена;

КонецЕсли;

КонецЦикла;

Метод Найти выполняет линейный поиск, поэтому на больших таблицах такой цикл работает медленно. Ускорить его можно двумя способами. Первый — построить индекс: Таблица2.Индексы.Добавить("Номенклатура") перед циклом. Второй — один раз собрать соответствие, где ключ — значение ключевой колонки, а значение — строка таблицы, и искать уже в нём:

ИндексТ2 = Новый Соответствие;

Для Каждого СтрокаТ2 Из Таблица2 Цикл

ИндексТ2.Вставить(СтрокаТ2.Номенклатура, СтрокаТ2);

КонецЦикла;

Для Каждого СтрокаТ1 Из Таблица1 Цикл

СтрокаТ2 = ИндексТ2[СтрокаТ1.Номенклатура];

Если СтрокаТ2 <> Неопределено Тогда

СтрокаТ1.Цена = СтрокаТ2.Цена;

КонецЕсли;

КонецЦикла;

Если по одному ключу во второй таблице может быть несколько строк, используйте НайтиСтроки со структурой отбора — она вернёт массив всех совпадений. В соответствии-индексе в этом случае храните массив строк, а не одну строку.

Соответствие в качестве индекса почти всегда выигрывает у метода Найти уже на нескольких тысячах строк: поиск по соответствию работает за постоянное время, а Найти перебирает таблицу заново для каждой строки. Строить соответствие — один проход по таблице, это дёшево.
ПЗ
Практическое замечание

Сравнение подходов и их ограничения

У каждого способа есть условия применимости, и выбирать стоит осознанно, а не по привычке.

СпособКогда подходитОграничения
Цикл с ДобавитьСклейка таблиц одинаковой структурыНе соединяет по ключу, дубли убираются отдельно
Запрос к временным таблицамСоединение по ключу, большие объёмы, нужны виды JOINТребует строгих типов колонок, больше кода
Перебор с Найти/НайтиСтрокиНебольшие таблицы, простая логикаМедленно на больших объёмах без индекса
Перебор с соответствием-индексомСредние объёмы, гибкая логика сопоставленияРучная реализация, нет готовых LEFT/RIGHT JOIN

Запрос к временным таблицам — самый универсальный вариант, но он требует аккуратности с типами. Перебор с соответствием проще отлаживать и в нём легко реализовать нестандартные правила: например, сопоставление по нескольким колонкам сразу (ключ собирается конкатенацией) или поиск с нечётким условием.

Сравнение вариантов

Запрос с временными таблицами

Быстро на больших данных, полный набор соединений. Требует типизированных колонок и серверного контекста для максимальной эффективности

Перебор с соответствием

Прозрачная логика, легко отлаживать, гибкие условия связи. Код длиннее, виды соединений реализуются вручную

Простая склейка циклом

Минимум кода для таблиц с одинаковой структурой. Не решает задачу соединения по ключу

Типичные ошибки при соединении таблиц

Большинство проблем при объединении таблиц значений связаны не с синтаксисом, а с данными. Самая частая — дубли ключа во второй таблице: при соединении один-ко-многим строки первой таблицы размножаются, и итоговые суммы завышаются. Перед соединением проверьте уникальность ключа или осознанно сверните вторую таблицу.

Вторая группа ошибок — несовпадение типов и представлений ключа. Строка «000123» и число 123 не равны, ссылка на элемент справочника и её строковое представление — тоже. Если таблицы пришли из разных источников (одна из базы, другая из Excel), приведите ключи к одному типу до соединения, иначе получите пустой результат без единой ошибки.

Третья ошибка — модификация таблицы внутри цикла по ней же. Добавление или удаление строк таблицы, по которой идёт Для Каждого, приводит к пропуску строк или ошибке. Результат собирайте в отдельную таблицу.

Типичные ошибки
01
Соединение по ключу с дублями во второй таблице — строки размножаются, суммы завышаются
02
Разные типы ключевых колонок (число против строки) — соединение молча не находит ни одной пары
03
Игнорирование NULL после левого соединения — ошибки в последующих расчётах и сравнениях
04
Изменение таблицы внутри цикла перебора по ней же — пропущенные строки или исключение
05
Свертка исходной таблицы без копии — безвозвратная потеря детальных данных

Проверка результата соединения

После соединения обязательно убедитесь, что результат соответствует ожиданиям, прежде чем передавать его дальше — в проведение документа, выгрузку или отчёт. Минимальный набор проверок: количество строк, контрольные суммы и доля несопоставленных записей.

Для левого соединения число строк результата должно быть не меньше числа строк первой таблицы (больше — только если во второй таблице есть дубли ключа). Сумма по числовой колонке первой таблицы до и после соединения должна совпадать — это быстрый способ поймать размножение строк. Строки с NULL в присоединённых колонках стоит вывести отдельно и разобраться, почему для них не нашлось пары.

Контрольные точки

Как проверить результат

Число строк результата
Норма

Равно числу строк первой таблицы при уникальном ключе

Тревожный признак

Строк больше — во второй таблице дубли ключа

Итог по суммовой колонке
Норма

Совпадает с итогом до соединения

Тревожный признак

Итог вырос — строки размножились соединением

Пустые значения присоединённых колонок
Норма

Только для заведомо несопоставимых ключей

Тревожный признак

Массовые NULL — не совпадают типы или форматы ключей

Количество строк после склейки
Норма

Равно сумме строк обеих таблиц

Тревожный признак

Меньше — часть строк потеряна при переносе

FAQ

Можно ли соединить таблицы значений без запроса, одной командой?

Встроенного метода соединения нет. Минимальный вариант — цикл с ЗаполнитьЗначенияСвойств для склейки таблиц одинаковой структуры. Для соединения по ключу придётся писать перебор с поиском либо использовать запрос к временным таблицам.

Почему запрос с параметром-таблицей выдаёт ошибку о типе колонки?

Платформа должна однозначно определить тип каждой колонки передаваемой таблицы. Если колонка создана без явного типа или ни в одной строке не заполнена, тип определить невозможно. Создавайте колонки через ТаблицаЗначений.Колонки.Добавить с указанием ОписаниеТипов.

Как реализовать полное внешнее соединение без запроса?

Двумя проходами: сначала перебрать первую таблицу и подтянуть совпадения из второй, помечая использованные строки второй таблицы (например, в соответствии). Затем перебрать вторую таблицу и добавить в результат все непомеченные строки.

Что делать, если ключ состоит из нескольких колонок?

В запросе перечислите все условия связи через И в секции ПО. При переборе с соответствием соберите составной ключ конкатенацией значений с разделителем, например Строка(Склад) + "|" + Строка(Номенклатура), и используйте его как ключ соответствия.

Как убрать дубли после склейки двух таблиц?

Используйте метод Свернуть с перечнем колонок группировки. Если нужно сохранить суммы по числовым полям, укажите их вторым параметром. Помните, что свёртка изменяет исходную таблицу — при необходимости работайте с копией.

Что быстрее: запрос или перебор с соответствием?

На больших таблицах запрос к временным таблицам обычно быстрее, так как соединение выполняется оптимизированными механизмами платформы. На малых объёмах разница незаметна, и перебор с соответствием выигрывает за счёт простоты отладки и гибкости логики.

Итог

Что важно запомнить

Склейку таблиц одинаковой структуры делайте циклом с ЗаполнитьЗначенияСвойств, соединение по ключу — запросом к временным таблицам либо перебором с соответствием-индексом. Перед соединением приведите типы ключей к одному виду и проверьте уникальность ключа, после — сверьте число строк и контрольные суммы.