Разработка и Конфигурация · 12 мин
Как объединить строки в таблице значений 1С
Как объединить строки в таблице значений 1С: метод Свернуть(), группировка через запрос, объединение таблиц. Примеры кода, ошибки и проверка результата.
Объединение строк в таблице значений — одна из самых частых задач при разработке на платформе 1С:Предприятие. Типовой сценарий: в таблице несколько строк с одинаковой номенклатурой, контрагентом или договором, и нужно получить одну строку на каждую комбинацию ключевых полей с суммированием количества и суммы. Для этого существует штатный метод Свернуть(), а для более сложных случаев — группировка через запрос и ручной обход.
Выбор способа зависит от условий: нужно ли просто просуммировать числовые колонки, требуется ли агрегировать строки нестандартным образом (например, собрать список документов через запятую), важна ли производительность на больших объёмах. Ниже разобраны все рабочие варианты с примерами кода и границами применения.
Важно понимать терминологию: «объединить строки» может означать две разные операции — свёртку внутри одной таблицы (группировку дублей) и слияние двух таблиц в одну. Оба сценария рассмотрены в статье.
Метод Свернуть() — основной способ объединения строк
Метод Свернуть() — встроенный инструмент таблицы значений, который группирует строки по указанным колонкам и суммирует значения в колонках суммирования. Синтаксис: ТаблицаЗначений.Свернуть(КолонкиГруппировки, КолонкиСуммирования), где оба параметра — строки с именами колонок через запятую.
Типовой пример: есть таблица товаров, где одна номенклатура встречается несколько раз с разным количеством. Чтобы получить итог по каждому товару, достаточно одной строки кода:
ТЗ.Свернуть("Номенклатура", "Количество, Сумма");
После выполнения в таблице останутся только колонки, перечисленные в параметрах: Номенклатура, Количество, Сумма. Все остальные колонки будут удалены без возможности восстановления — это ключевая особенность метода, о которой часто забывают.
Если второй параметр (колонки суммирования) не указать, метод просто удалит дубли строк по колонкам группировки — это удобный способ получить уникальные комбинации значений. Например, ТЗ.Свернуть("Контрагент, Договор") вернёт список уникальных пар «контрагент-договор».
Как сохранить исходные данные при свёртке
Поскольку Свернуть() работает «на месте» и разрушает структуру таблицы, безопасный приём — сворачивать копию. Метод Скопировать() создаёт полную независимую копию таблицы со всеми строками и колонками:
ТЗСвернуто = ТЗ.Скопировать();
ТЗСвернуто.Свернуть("Номенклатура, Склад", "Количество");
Альтернатива — выгрузить только нужные колонки в новую таблицу методом ВыгрузитьКолонку() не подходит, но можно скопировать с отбором колонок: ТЗ.Скопировать(, "Номенклатура, Количество, Сумма"). Второй параметр задаёт список колонок, которые попадут в копию, что сразу отсекает лишнее.
При работе с табличными частями документов метод Выгрузить() преобразует табличную часть в таблицу значений, после чего её можно свободно сворачивать, не затрагивая данные документа:
ТЗ = ДокументОбъект.Товары.Выгрузить();
ТЗ.Свернуть("Номенклатура", "Количество, Сумма");
- 1Определите колонки группировки — по каким полям строки считаются дублями
- 2Определите колонки суммирования — какие числовые поля нужно сложить
- 3Сделайте копию таблицы методом Скопировать(), если исходная ещё нужна
- 4Выполните Свернуть() с двумя параметрами через запятую
- 5Проверьте результат: количество строк уменьшилось, итоги по суммам совпадают с исходными
Группировка через запрос для сложных сценариев
Когда данных много или нужны агрегаты, отличные от суммы (минимум, максимум, среднее, количество различных), эффективнее использовать запрос. Таблицу значений можно передать в запрос как параметр через временную таблицу:
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.Текст =
"ВЫБРАТЬ
| ТЗ.Номенклатура КАК Номенклатура,
| ТЗ.Количество КАК Количество
|ПОМЕСТИТЬ ВТ
|ИЗ &ТЗ КАК ТЗ
|;
|ВЫБРАТЬ
| ВТ.Номенклатура,
| СУММА(ВТ.Количество) КАК Количество
|ИЗ ВТ КАК ВТ
|СГРУППИРОВАТЬ ПО ВТ.Номенклатура";
Запрос.УстановитьПараметр("ТЗ", ТЗ);
Результат = Запрос.Выполнить().Выгрузить();
Такой подход оправдан при объёмах от десятков тысяч строк: серверная СУБД выполнит группировку заметно быстрее, чем встроенный язык. Кроме того, запрос позволяет сразу соединить таблицу со справочниками и получить дополнительные поля (артикул, единицу измерения), не делая отдельных обходов.
Ограничение: передача таблицы в запрос требует, чтобы типы колонок были определены однозначно. Колонки с составным типом «произвольного» вида могут вызвать ошибку при помещении во временную таблицу — в этом случае типизируйте колонки при создании таблицы через ОписаниеТипов.
Сравнение вариантов
Подходит для простой суммовой группировки в памяти. Ограничение: только сумма, удаляет лишние колонки, медленно на очень больших таблицах.
Подходит для больших объёмов и нестандартных агрегатов (МИНИМУМ, МАКСИМУМ, КОЛИЧЕСТВО РАЗЛИЧНЫХ). Требует типизированных колонок и больше кода.
Подходит, когда агрегация нестандартная: склеить строки, собрать массив значений. Гибко, но медленнее и больше кода.
Нестандартная агрегация: склейка строк и сбор значений
Метод Свернуть() умеет только суммировать. Если нужно объединить строки, собрав текстовые значения через запятую (например, список номеров документов по контрагенту), используйте ручной обход с соответствием:
Группы = Новый Соответствие;
Для Каждого Строка Из ТЗ Цикл
Запись = Группы.Получить(Строка.Контрагент);
Если Запись = Неопределено Тогда
Запись = Новый Структура("Документы, Сумма", "", 0);
Группы.Вставить(Строка.Контрагент, Запись);
КонецЕсли;
Запись.Документы = ?(Запись.Документы = "", "", Запись.Документы + ", ") + Строка.НомерДокумента;
Запись.Сумма = Запись.Сумма + Строка.Сумма;
КонецЦикла;
После обхода соответствие можно выгрузить в новую таблицу значений или обработать напрямую. Такой приём универсален: внутри цикла доступна любая логика — конкатенация, подсчёт уникальных значений, сбор массивов.
Для склейки строк в запросе на некоторых СУБД доступны строковые агрегаты, но в языке запросов 1С их нет, поэтому ручной обход остаётся основным решением для текстовой агрегации.
Как объединить две таблицы значений в одну
Вторая трактовка задачи — слить строки двух таблиц в одну. Если структуры колонок совпадают, достаточно цикла:
Для Каждого Строка Из ТЗ2 Цикл
НоваяСтрока = ТЗ1.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, Строка);
КонецЦикла;
ЗаполнитьЗначенияСвойств() переносит значения по совпадающим именам колонок, поэтому лишние колонки во второй таблице не вызовут ошибку — они просто не перенесутся. Если колонки называются по-разному, присваивайте значения явно.
Для больших таблиц быстрее объединение через запрос с конструкцией ОБЪЕДИНИТЬ ВСЕ: обе таблицы передаются как параметры, помещаются во временные таблицы и объединяются одним запросом. Вариант ОБЪЕДИНИТЬ (без ВСЕ) дополнительно удалит полные дубли строк.
Перед объединением проверяйте типы колонок: если в одной таблице колонка Сумма имеет тип Число(15,2), а в другой Число(10,0), итоговая точность может отличаться от ожидаемой. Приведите описания типов к единому виду при создании таблиц.
Проверка результата и типичные ошибки
После свёртки или объединения результат стоит проверить, прежде чем передавать его дальше — в документ, отчёт или печатную форму. Контрольные точки: сумма по итоговой колонке до и после свёртки должна совпадать, количество строк не должно быть больше исходного, а все ключевые комбинации — присутствовать.
СуммаДо = ТЗ.Итог("Сумма");
ТЗКопия = ТЗ.Скопировать();
ТЗКопия.Свернуть("Номенклатура", "Сумма");
Если ТЗКопия.Итог("Сумма") <> СуммаДо Тогда
ВызватьИсключение "Итоги не совпадают после свёртки";
КонецЕсли;
Как проверить результат
Совпадает с итогом до свёртки
Итог изменился — возможно, часть строк потеряна или колонка не числовая
Строк стало меньше или столько же, каждая комбинация ключей уникальна
Остались дубли по ключевым полям — проверьте пробелы и регистр в строковых значениях
В таблице только колонки группировки и суммирования, этого достаточно для дальнейшей логики
Нужные дальше колонки пропали — свёртку выполняли не на копии
Производительность и ограничения
На таблицах до нескольких тысяч строк разница между Свернуть() и запросом практически незаметна. На десятках и сотнях тысяч строк запрос с временной таблицей обычно выигрывает, особенно в клиент-серверном варианте, где группировка выполняется на стороне СУБД без перекачки данных.
Ручной обход с соответствием — самый медленный вариант на больших объёмах, но единственный, когда логика агрегации нестандартная. Если коллекция, по которой идёт поиск, — массив вместо соответствия, сложность поиска растёт линейно, и на больших таблицах это становится узким местом: всегда используйте Соответствие для ключей.
Ещё одно ограничение Свернуть(): группировка идёт по точному совпадению значений всех перечисленных колонок. Если нужно сгруппировать по части значения (например, по месяцу даты или по первым символам кода), сначала добавьте вычисляемую колонку с ключом группировки и сворачивайте по ней.
Как выбрать действие
Частые вопросы
Можно ли свернуть таблицу, не удаляя остальные колонки?
Штатно нет: Свернуть() оставляет только указанные колонки. Обходной путь — свернуть копию, а затем при необходимости соединить результат с исходными данными через запрос или поиск по ключу.
Почему после Свернуть() остались дубли по номенклатуре?
Чаще всего причина в разных значениях, которые выглядят одинаково: лишние пробелы, разный регистр в строках или разные ссылки на элементы с одинаковым наименованием. Проверьте значения через СокрЛП() и сравнение ссылок.
Как свернуть табличную часть документа, не меняя сам документ?
Вызовите ДокументОбъект.Товары.Выгрузить() — получите независимую таблицу значений. Все операции с ней, включая Свернуть(), не затрагивают данные объекта до явной загрузки обратно методом Загрузить().
Что быстрее: Свернуть() или запрос?
На малых объёмах разницы нет, и Свернуть() проще в коде. На больших таблицах в клиент-серверной базе запрос с временной таблицей обычно быстрее, так как группировку выполняет СУБД.
Как объединить строки и посчитать количество сгруппированных строк?
Свернуть() этого не умеет. Используйте запрос с агрегатом КОЛИЧЕСТВО(*) либо ручной обход со счётчиком в структуре значения соответствия.
Можно ли свернуть по дате без времени?
Напрямую нет — группировка идёт по точному значению, а даты с разным временем считаются разными. Добавьте в таблицу колонку с усечённой датой (НачалоДня(Дата)) и сворачивайте по ней.
Что важно запомнить
Основной инструмент объединения строк — метод Свернуть(КолонкиГруппировки, КолонкиСуммирования), выполняемый на копии таблицы. Для нестандартных агрегатов и больших объёмов используйте запрос с СГРУППИРОВАТЬ ПО, для склейки текстов — обход с соответствием, а для слияния таблиц — цикл с ЗаполнитьЗначенияСвойств или ОБЪЕДИНИТЬ ВСЕ. После операции сверяйте итоги по суммовым колонкам с исходными.