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

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

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

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

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

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

Ниже разобраны все рабочие способы с примерами кода, условиями выбора и типичными ошибками. Материал ориентирован на 1С:Предприятие 8.3, но большинство приёмов работает и на более ранних версиях платформы.

Определите, какое именно «сложение» вам нужно

Прежде чем писать код, определите тип операции. От этого зависит и алгоритм, и производительность. Чаще всего встречаются три сценария.

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

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

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

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

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

Способ 1: добавить строки из одной таблицы в другую циклом

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

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

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

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

КонецЦикла;

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

Если нужно перенести только отдельные колонки, укажите их списком во втором параметре: ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаИсточник, "Номенклатура,Количество,Сумма"). Так вы защититесь от случайного переноса лишних данных.

Альтернатива без цикла — метод ЗагрузитьКолонку в связке с ВыгрузитьКолонку, но он заменяет значения существующей колонки, а не добавляет строки, поэтому для сложения таблиц подходит плохо. Для полного копирования одной таблицы в пустую есть метод Загрузить(Таблица2), но он полностью замещает содержимое приёмника — учитывайте это.

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

Универсальный и самый производительный способ — поместить обе таблицы во временные и объединить их запросом. Таблица значений передаётся в запрос как параметр через конструкцию ВЫБРАТЬ ... ПОМЕСТИТЬ с указанием источника &Таблица.

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

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

"ВЫБРАТЬ Т.Номенклатура, Т.Количество, Т.Сумма

|ПОМЕСТИТЬ Таб1 ИЗ &Таблица1 КАК Т

|;

|ВЫБРАТЬ Т.Номенклатура, Т.Количество, Т.Сумма

|ПОМЕСТИТЬ Таб2 ИЗ &Таблица2 КАК Т

|;

|ВЫБРАТЬ Т.Номенклатура, Т.Количество, Т.Сумма

|ИЗ Таб1 КАК Т

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

|ВЫБРАТЬ Т.Номенклатура, Т.Количество, Т.Сумма

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

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

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

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

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

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

Способ 3: сложить с суммированием по ключевым полям

На практике чаще всего требуется не просто дописать строки, а свести дубли: например, одна и та же номенклатура встречается в обеих таблицах, и её количество и сумму нужно просуммировать. Для этого после объединения применяют группировку.

Через запрос с группировкой

Дополните итоговую выборку из предыдущего примера группировкой и агрегатными функциями:

ВЫБРАТЬ Т.Номенклатура, СУММА(Т.Количество) КАК Количество,

СУММА(Т.Сумма) КАК Сумма

ИЗ (

ВЫБРАТЬ Т.Номенклатура, Т.Количество, Т.Сумма ИЗ Таб1 КАК Т

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

ВЫБРАТЬ Т.Номенклатура, Т.Количество, Т.Сумма ИЗ Таб2 КАК Т

) КАК Т

СГРУППИРОВАТЬ ПО Т.Номенклатура

Через метод Свернуть

Если таблицы уже сложены циклом, можно свернуть результат встроенным методом: Таблица1.Свернуть("Номенклатура", "Количество,Сумма"). Первый параметр — колонки группировки, второй — суммируемые колонки. Метод модифицирует таблицу «на месте»: все остальные колонки будут удалены, поэтому при необходимости сохраните исходник через Скопировать().

Выбор между запросом и Свернуть — вопрос объёма и контекста. На небольших таблицах разница незаметна; на крупных запрос быстрее и не требует предварительного слияния строк в памяти.

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

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

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

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

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

Свернуть после слияния

Минимум кода для суммирования по ключам, но уничтожает несуммируемые колонки и меняет исходную таблицу.

Способ 4: соединение таблиц по ключевой колонке

Когда задача — не дописать строки, а «пришить» к первой таблице колонки из второй по общему ключу (например, подтянуть цены к списку товаров), используется соединение. В запросе это ЛЕВОЕ СОЕДИНЕНИЕ по временным таблицам:

ВЫБРАТЬ Т1.Номенклатура, Т1.Количество, Т2.Цена

ИЗ Таб1 КАК Т1

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

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

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

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

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

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

КонецЦикла;

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

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

Если Найденная <> Неопределено Тогда

Строка.Цена = Найденная.Цена;

КонецЕсли;

КонецЦикла;

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

Проверка результата и типичные ошибки

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

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

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

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

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

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

Меньше — значит применялось ОБЪЕДИНИТЬ без ВСЕ или отбор отсёк строки

Сумма числовой колонки до и после Свернуть
Норма

Итог совпадает с суммой исходных таблиц

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

Расхождение — потеряны строки или тип колонки обрезал дробную часть

Значения ключевых колонок
Норма

Нет NULL и пустых ссылок после соединения

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

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

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

Числа остались числами с нужной точностью

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

Смешанные типы привели к NULL или ошибке запроса

Типичные ошибки
01
{'title': 'ОБЪЕДИНИТЬ без ВСЕ', 'text': 'Дубли строк исчезают из результата — итоги занижаются, причём молча.'}
02
{'title': 'Загрузить() вместо добавления', 'text': 'Метод полностью замещает содержимое приёмника, существующие строки теряются.'}
03
{'title': 'Свернуть на исходной таблице', 'text': 'Метод удаляет все колонки, не перечисленные в параметрах, и меняет таблицу на месте. Работайте с копией.'}
04
{'title': 'Найти() внутри цикла по большой таблице', 'text': 'Квадратичная сложность: на десятках тысяч строк код выполняется минутами. Используйте соответствие или запрос.'}
05
{'title': 'Несовпадение типов колонок', 'text': 'При передаче в запрос смешанные типы дают NULL или ошибку. Задавайте типы явно при создании колонок.'}

Ещё одна тонкость — модификация таблицы во время её обхода. Если вы добавляете строки в таблицу, по которой идёт цикл Для Каждого, обход может стать бесконечным или поведение окажется неочевидным. Добавляйте строки в другую таблицу-приёмник либо обходите копию.

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

Частые вопросы

Можно ли сложить таблицы с разным набором колонок?

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

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

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

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

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

Как сложить таблицы, не меняя исходные?

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

Почему после объединения в запросе появились NULL в числовых колонках?

Обычно причина в несовпадении типов колонок исходных таблиц: например, в одной колонка имеет составной тип «Число + Строка». Приведите колонки к единому типу при создании таблицы через ОписаниеТипов или используйте ВЫРАЗИТЬ в запросе. Также NULL появляется при левом соединении, если пару по ключу не нашли.

Как удалить дубли строк после сложения?

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

Итог

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

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