Разработка и Конфигурация · 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 или ошибке запроса
Ещё одна тонкость — модификация таблицы во время её обхода. Если вы добавляете строки в таблицу, по которой идёт цикл Для Каждого, обход может стать бесконечным или поведение окажется неочевидным. Добавляйте строки в другую таблицу-приёмник либо обходите копию.
Если таблицы складываются в цикле многократно (например, накапливаются результаты по каждому документу), не вызывайте Свернуть на каждой итерации — сверните один раз в конце. Это заметно сокращает время выполнения обработки.
Частые вопросы
Можно ли сложить таблицы с разным набором колонок?
Да. В цикле ЗаполнитьЗначенияСвойств перенесёт только совпадающие по именам колонки. В запросе нужно явно выровнять состав полей: недостающие колонки подставьте как NULL или значение по умолчанию, иначе объединение не скомпилируется — число и порядок полей в объединяемых выборках должны совпадать.
Как объединить три и больше таблиц значений?
Теми же способами. В запросе добавьте дополнительные секции ОБЪЕДИНИТЬ ВСЕ для каждой таблицы. В цикле — обходите массив таблиц и добавляйте строки в общий приёмник. Группировка и свёртка выполняются один раз над итоговым результатом.
Что быстрее: запрос или цикл?
На таблицах до нескольких тысяч строк разница практически незаметна, и проще писать цикл. На десятках тысяч строк и выше запрос с временными таблицами выигрывает многократно, особенно если нужна группировка или соединение по ключу.
Как сложить таблицы, не меняя исходные?
Создайте новую пустую таблицу с нужными колонками и добавляйте строки из обеих исходных в неё. Либо начните с копии: Результат = Таблица1.Скопировать(), а затем добавьте строки из второй таблицы. Помните, что Свернуть и Загрузить модифицируют объект, у которого вызваны.
Почему после объединения в запросе появились NULL в числовых колонках?
Обычно причина в несовпадении типов колонок исходных таблиц: например, в одной колонка имеет составной тип «Число + Строка». Приведите колонки к единому типу при создании таблицы через ОписаниеТипов или используйте ВЫРАЗИТЬ в запросе. Также NULL появляется при левом соединении, если пару по ключу не нашли.
Как удалить дубли строк после сложения?
Используйте ОБЪЕДИНИТЬ без ВСЕ в запросе — дубли полностью совпадающих строк будут убраны. Без запроса: вызовите Свернуть, указав в первом параметре все колонки, а суммируемые оставив пустыми — либо программно проверяйте наличие строки через соответствие перед добавлением.
Что важно запомнить
Для простого добавления строк достаточно цикла с ЗаполнитьЗначенияСвойств. Для объединения с суммированием и соединения по ключу надёжнее и быстрее запрос с ОБЪЕДИНИТЬ ВСЕ и временными таблицами. Следите за типами колонок, не теряйте данные через Загрузить и Свернуть, а результат всегда проверяйте контрольными суммами.