Разработка и Конфигурация · 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), приведите ключи к одному типу до соединения, иначе получите пустой результат без единой ошибки.
Третья ошибка — модификация таблицы внутри цикла по ней же. Добавление или удаление строк таблицы, по которой идёт Для Каждого, приводит к пропуску строк или ошибке. Результат собирайте в отдельную таблицу.
Проверка результата соединения
После соединения обязательно убедитесь, что результат соответствует ожиданиям, прежде чем передавать его дальше — в проведение документа, выгрузку или отчёт. Минимальный набор проверок: количество строк, контрольные суммы и доля несопоставленных записей.
Для левого соединения число строк результата должно быть не меньше числа строк первой таблицы (больше — только если во второй таблице есть дубли ключа). Сумма по числовой колонке первой таблицы до и после соединения должна совпадать — это быстрый способ поймать размножение строк. Строки с NULL в присоединённых колонках стоит вывести отдельно и разобраться, почему для них не нашлось пары.
Как проверить результат
Равно числу строк первой таблицы при уникальном ключе
Строк больше — во второй таблице дубли ключа
Совпадает с итогом до соединения
Итог вырос — строки размножились соединением
Только для заведомо несопоставимых ключей
Массовые NULL — не совпадают типы или форматы ключей
Равно сумме строк обеих таблиц
Меньше — часть строк потеряна при переносе
FAQ
Можно ли соединить таблицы значений без запроса, одной командой?
Встроенного метода соединения нет. Минимальный вариант — цикл с ЗаполнитьЗначенияСвойств для склейки таблиц одинаковой структуры. Для соединения по ключу придётся писать перебор с поиском либо использовать запрос к временным таблицам.
Почему запрос с параметром-таблицей выдаёт ошибку о типе колонки?
Платформа должна однозначно определить тип каждой колонки передаваемой таблицы. Если колонка создана без явного типа или ни в одной строке не заполнена, тип определить невозможно. Создавайте колонки через ТаблицаЗначений.Колонки.Добавить с указанием ОписаниеТипов.
Как реализовать полное внешнее соединение без запроса?
Двумя проходами: сначала перебрать первую таблицу и подтянуть совпадения из второй, помечая использованные строки второй таблицы (например, в соответствии). Затем перебрать вторую таблицу и добавить в результат все непомеченные строки.
Что делать, если ключ состоит из нескольких колонок?
В запросе перечислите все условия связи через И в секции ПО. При переборе с соответствием соберите составной ключ конкатенацией значений с разделителем, например Строка(Склад) + "|" + Строка(Номенклатура), и используйте его как ключ соответствия.
Как убрать дубли после склейки двух таблиц?
Используйте метод Свернуть с перечнем колонок группировки. Если нужно сохранить суммы по числовым полям, укажите их вторым параметром. Помните, что свёртка изменяет исходную таблицу — при необходимости работайте с копией.
Что быстрее: запрос или перебор с соответствием?
На больших таблицах запрос к временным таблицам обычно быстрее, так как соединение выполняется оптимизированными механизмами платформы. На малых объёмах разница незаметна, и перебор с соответствием выигрывает за счёт простоты отладки и гибкости логики.
Что важно запомнить
Склейку таблиц одинаковой структуры делайте циклом с ЗаполнитьЗначенияСвойств, соединение по ключу — запросом к временным таблицам либо перебором с соответствием-индексом. Перед соединением приведите типы ключей к одному виду и проверьте уникальность ключа, после — сверьте число строк и контрольные суммы.