Почему метод Свернуть() в таблице значений 1С не срабатывает и как это исправить?

Программист 1С v8.3 (Обычные формы) Управленческий учет
← На главную

В процессе разработки на платформе 1С:Предприятие 8 часто возникает задача группировки данных. Основным инструментом для этого в оперативной памяти является метод Свернуть() объекта ТаблицаЗначений. Однако начинающие разработчики часто сталкиваются с ситуацией, когда метод вызывается, но строки с одинаковыми ключевыми полями остаются на месте. Рассмотрим подробно, почему это происходит, и проанализируем правильные подходы к решению этой задачи.

Разбор основной логической ошибки: порядок выполнения команд

Проанализируем фрагмент кода, который часто становится причиной недоумения. Основная ошибка заключается не в самом методе, а в алгоритмическом порядке действий. Рассмотрим ситуацию, когда разработчик сначала инициализирует таблицу, сразу вызывает метод Свернуть(), а затем начинает наполнять её данными в цикле.

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

  1. Создание объекта ТаблицаЗначений и определение его колонок (в этом поможет генератор, создающий код новой таблицы значений).
  2. Цикл обхода источника данных (например, ТабличныйДокумент или файл Excel) и заполнение таблицы всеми строками, включая дубли.
  3. Вызов метода Свернуть() после завершения цикла заполнения.
  4. Дальнейшая обработка уже свернутых данных (например, запись в документы или справочники).

Посмотрим на пример правильной последовательности действий:


// 1. Создаем и типизируем ТЗ
ДанныеФайла = Новый ТаблицаЗначений;
ДанныеФайла.Колонки.Добавить("НомерЗаказа", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(20)));
ДанныеФайла.Колонки.Добавить("СуммаДоставки", Новый ОписаниеТипов("Число", , , Новый КвалификаторыЧисла(15,2)));

// 2. Заполняем ТЗ всеми данными из источника
Для НомерСтроки = 2 По ТабДок.ВысотаТаблицы Цикл
    НоваяСтрока = ДанныеФайла.Добавить();
    НоваяСтрока.НомерЗаказа = СокрЛП(ТабДок.Область(НомерСтроки, 1).Текст);
    // Обязательно приводим к числу, чтобы метод Свернуть корректно суммировал
    НоваяСтрока.СуммаДоставки = Число(ТабДок.Область(НомерСтроки, 2).Текст);
КонецЦикла;

// 3. Вот теперь сворачиваем!
// Первый параметр - колонки группировки, второй - колонки суммирования
ДанныеФайла.Свернуть("НомерЗаказа", "СуммаДоставки");

// 4. Обрабатываем результат
Для Каждого СтрокаТЗ Из ДанныеФайла Цикл
    // Здесь выполняем действия с уникальными заказами
КонецЦикла;

Проблема типов данных и невидимых символов

Даже если мы вызываем метод в правильном месте, строки могут не свернуться. Разберем вторую по частоте причину — неявное различие в значениях. Для метода Свернуть() значения " 123" и "123" — это разные ключи группировки.

Рассмотрим подробнее факторы, влияющие на сравнение:

  1. Пробелы: При чтении из текстовых документов или Excel в строке часто присутствуют лишние пробелы. Всегда используйте функцию СокрЛП() при заполнении таблицы.
  2. Типизация колонок: Если одна строка содержит число 100, а другая — строку "100", 1С не сможет их свернуть. При добавлении колонок в таблицу значений крайне важно использовать ОписаниеТипов. Это гарантирует, что при присваивании значения оно будет автоматически приведено к нужному типу.
  3. Неразрывные пробелы: Часто в финансовых данных встречается символ с кодом 160 (неразрывный пробел), который используется как разделитель разрядов. Стандартная функция СокрЛП() его не удаляет. В таких случаях нужно использовать СтрЗаменить(Текст, Символы.НПП, "").

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

Архитектурная ошибка: "Запрос в цикле"

Часто в процессе группировки разработчики пытаются выполнять бизнес-логику (например, поиск документа по номеру и его проведение) прямо внутри цикла заполнения таблицы. Это приводит к двум негативным последствиям:

  1. Дублирование операций: Если один и тот же заказ встречается в файле 10 раз, документ будет найден, изменен и записан 10 раз вместо одного.
  2. Низкая производительность: Каждое обращение к базе данных (НайтиПоНомеру, Записать) — это тяжелая операция.

Рассмотрим, как правильно организовать процесс обработки данных. Нам нужно разделить чтение и обработку на два независимых этапа. Проанализируем пример кода, где мы сначала собираем данные, сворачиваем их, а затем работаем с объектами базы данных:


// Этап 1: Сбор данных
ТЗ_Заказы = Новый ТаблицаЗначений;
ТЗ_Заказы.Колонки.Добавить("НомерЗаказа", Новый ОписаниеТипов("Строка"));
ТЗ_Заказы.Колонки.Добавить("Сумма", Новый ОписаниеТипов("Число"));

Для НомерСтроки = 2 По Высота Цикл
    Стр = ТЗ_Заказы.Добавить();
    Стр.НомерЗаказа = СокрЛП(ОбластьНомер.Текст);
    Стр.Сумма = Число(ОбластьСумма.Текст);
КонецЦикла;

// Этап 2: Группировка
ТЗ_Заказы.Свернуть("НомерЗаказа", "Сумма");

// Этап 3: Обработка объектов БД
Для Каждого ТекущийЗаказ Из ТЗ_Заказы Цикл
    СсылкаНаЗаказ = Документы.ЗаказПокупателя.НайтиПоНомеру(ТекущийЗаказ.НомерЗаказа, ДатаНачалаПоиска);
    
    Если СсылкаНаЗаказ.Пустая() Тогда
        Сообщить("Заказ не найден: " + ТекущийЗаказ.НомерЗаказа);
        Продолжить;
    КонецЕсли;
    
    // Работаем с объектом один раз для всех строк файла по этому заказу
    ОбъектЗаказа = СсылкаНаЗаказ.ПолучитьОбъект();
    ОбъектЗаказа.СтоимостьДоставки = ТекущийЗаказ.Сумма;
    ОбъектЗаказа.Записать(РежимЗаписиДокумента.Проведение);
КонецЦикла;

Продвинутый уровень: Использование запросов вместо ТЗ

Если данных очень много (десятки тысяч строк), даже метод Свернуть() может работать медленнее, чем хотелось бы. В таких случаях мы рекомендуем рассмотреть вариант с использованием Временных таблиц в запросе. Вы можете загрузить заполненную таблицу значений (еще не свернутую) в запрос, и с помощью предложения СГРУППИРОВАТЬ ПО получить результат. Запросы в 1С работают на уровне SQL-сервера и оптимизированы для подобных задач гораздо лучше, чем методы коллекции ТаблицаЗначений.

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

← На главную