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

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

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

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

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

Простейший путь — перебрать строки одной таблицы и добавить их в другую через Добавить() и ЗаполнитьЗначенияСвойств(). Более мощный вариант — выгрузить обе таблицы во временные таблицы запроса и объединить их оператором ОБЪЕДИНИТЬ или ОБЪЕДИНИТЬ ВСЕ. У каждого подхода есть свои ограничения по производительности и требования к типам колонок.

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

Способ 1: объединение через цикл и ЗаполнитьЗначенияСвойств

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

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

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

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

КонецЦикла;

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

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

bsl
Для Каждого СтрокаТЗ Из Таблица2 Цикл
    НоваяСтрока = Таблица1.Добавить();
    ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаТЗ);
КонецЦикла;

Способ 2: объединение через запрос с ОБЪЕДИНИТЬ ВСЕ

Когда таблицы большие или после объединения нужны сортировка, группировка, итоги или соединение с данными базы, выгоднее использовать запрос. Обе таблицы передаются как параметры, помещаются во временные таблицы и объединяются оператором ОБЪЕДИНИТЬ ВСЕ.

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

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

"ВЫБРАТЬ

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

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

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

|ИЗ &Таблица1 КАК Т

|;

|ВЫБРАТЬ

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

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

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

|ИЗ &Таблица2 КАК Т

|;

|ВЫБРАТЬ

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

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

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

|

|ОБЪЕДИНИТЬ ВСЕ

|

|ВЫБРАТЬ

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

| Таб2.Количество

|ИЗ Таб2 КАК Таб2";

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

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

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

Разница между ОБЪЕДИНИТЬ и ОБЪЕДИНИТЬ ВСЕ принципиальна. ОБЪЕДИНИТЬ убирает полностью совпадающие строки (дубликаты), ОБЪЕДИНИТЬ ВСЕ оставляет все строки как есть и работает быстрее. Если вам нужно именно сложение двух наборов данных — почти всегда используйте ОБЪЕДИНИТЬ ВСЕ.

Что делать, если структуры колонок различаются

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

Для метода с циклом добавьте недостающие колонки в первую таблицу перед копированием:

Для Каждого Колонка Из Таблица2.Колонки Цикл

Если Таблица1.Колонки.Найти(Колонка.Имя) = Неопределено Тогда

Таблица1.Колонки.Добавить(Колонка.Имя, Колонка.ТипЗначения);

КонецЕсли;

КонецЦикла;

Для запроса в каждой выборке явно перечислите одинаковый набор полей, а отсутствующие поля замените константами — NULL или значениями по умолчанию. Следите за совместимостью типов: если в первой выборке поле ссылочного типа, а во второй вы передаёте NULL, приведите его через ВЫРАЗИТЬ(NULL КАК Справочник.Номенклатура), иначе запрос может вернуть смешанный тип, который потом мешает соединениям и итогам.

Как убрать дубли и свернуть результат

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

Таблица1.Свернуть("Номенклатура", "Количество,Сумма");

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

В запросе аналогичный результат даёт группировка с СУММА() после ОБЪЕДИНИТЬ ВСЕ. Этот вариант предпочтительнее, когда группировку нужно совместить с отбором или соединением с другими данными — всё выполняется одним обращением к базе.

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

Цикл + ЗаполнитьЗначенияСвойств

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

Запрос с ОБЪЕДИНИТЬ ВСЕ

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

Свернуть() после цикла

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

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

Одна из самых частых проблем — несовпадение типов колонок. Например, в первой таблице колонка «Количество» имеет тип Число(15,2), а во второй — Число(15,3). При копировании через ЗаполнитьЗначенияСвойств() значения будут приведены к типу целевой колонки с округлением, и итоги «поплывут». Проверяйте типы через Таблица.Колонки.Найти("Количество").ТипЗначения до объединения.

Вторая ошибка — модификация таблицы, по которой идёт обход. Если вы добавляете строки первой таблицы в саму себя внутри цикла Для Каждого, получите бесконечный цикл или непредсказуемый результат. Решение — обходить копию: Для Каждого СтрокаТЗ Из Таблица1.Скопировать() Цикл.

Третья типичная ситуация — потеря индексов. Если до объединения вы строили индекс по колонкам через Таблица.Индексы.Добавить(), после массового добавления строк поиск может замедлиться. Пересоздайте индексы после завершения объединения, а не до него.

Типичные ошибки
01
Разные типы одноимённых колонок — при копировании значения округляются или обрезаются, итоги расходятся с источником.
02
Добавление строк в таблицу внутри обхода этой же таблицы — бесконечный цикл или пропуск строк; обходите копию.
03
Использование ОБЪЕДИНИТЬ вместо ОБЪЕДИНИТЬ ВСЕ — одинаковые строки молча схлопываются, и количество записей меньше ожидаемого.
04
Свернуть() на оригинале таблицы — удаляются все колонки вне списков группировки и сумм, исходные данные теряются.

Как проверить результат объединения

Минимальная проверка — сравнить количество строк: после объединения через цикл или ОБЪЕДИНИТЬ ВСЕ оно должно равняться сумме строк обеих исходных таблиц. Если строк меньше — где-то сработало удаление дублей или потеря данных.

Вторая проверка — контрольные суммы. До объединения посчитайте итог по числовой колонке в каждой таблице через Таблица.Итог("Сумма"), после — в результате. Итог результата должен равняться сумме исходных итогов. Расхождение указывает на приведение типов, потерю строк или ошибку в группировке.

Для отладки удобно временно добавить в каждую таблицу служебную колонку-источник («Таб1» / «Таб2») и после объединения свернуть результат по ней — вы сразу увидите, сколько строк пришло из каждого набора и не потерялась ли часть данных.

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

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

Количество строк результата
Норма

Равно сумме строк обеих таблиц (для ОБЪЕДИНИТЬ ВСЕ и цикла)

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

Строк меньше — сработало удаление дублей или потеря данных

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

Итог результата равен сумме итогов исходных таблиц

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

Расхождение — проверяйте типы колонок и точность

Типы колонок результата
Норма

Совпадают с типами исходных таблиц

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

Смешанный или усечённый тип — проблемы в соединениях дальше

FAQ: частые вопросы

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

Штатного метода вида «ДобавитьТаблицу» у таблицы значений нет. Единственные встроенные варианты — построчное копирование в цикле или запрос с ОБЪЕДИНИТЬ ВСЕ. Если таблицы получены из запросов, проще объединить их ещё на этапе текста запроса, не создавая промежуточные таблицы значений.

Чем ОБЪЕДИНИТЬ отличается от ОБЪЕДИНИТЬ ВСЕ?

ОБЪЕДИНИТЬ исключает полностью совпадающие строки из результата, ОБЪЕДИНИТЬ ВСЕ сохраняет все строки обеих выборок. Второй вариант быстрее, так как не требует сравнения строк. Для задачи «сложить две таблицы» почти всегда нужен именно ОБЪЕДИНИТЬ ВСЕ.

Почему после объединения в запросе поле стало строкой или потеряло тип?

В объединяемых выборках типы одноимённых полей должны быть совместимы. Если в одной выборке поле ссылочное, а в другой — NULL без приведения, итоговый тип может стать составным. Используйте ВЫРАЗИТЬ(NULL КАК НужныйТип), чтобы зафиксировать тип поля.

Как объединить три и более таблиц значений?

Через цикл — последовательно добавляйте каждую таблицу в итоговую. В запросе — перечислите все выборки через ОБЪЕДИНИТЬ ВСЕ, количество объединяемых источников не ограничено двумя. Предварительно приведите структуры всех таблиц к одинаковому набору колонок.

Что быстрее: цикл или запрос?

На небольших таблицах (сотни — тысячи строк) разница незаметна, и цикл проще в отладке. На больших объёмах запрос с ОБЪЕДИНИТЬ ВСЕ обычно быстрее, особенно если сразу нужны группировка или соединение с данными базы. Но передача таблицы параметром тоже стоит ресурсов — замеряйте на реальных данных.

Как объединить таблицы, чтобы дубли по ключу заменялись, а не добавлялись?

Это уже не объединение, а обновление по ключу. Используйте поиск: перед добавлением строки ищите её в целевой таблице через Найти() или НайтиСтроки() и обновляйте существующую строку вместо добавления новой. Для ускорения поиска добавьте индекс по ключевой колонке.

Итог

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

Для одинаковых структур используйте цикл с ЗаполнитьЗначенияСвойств() или запрос с ОБЪЕДИНИТЬ ВСЕ; для разных — сначала приведите колонки к общему виду. Свернуть() удаляет неуказанные колонки, поэтому работайте с копией. Результат проверяйте по количеству строк и контрольным итогам числовых колонок.