В процессе разработки в среде "1С:Предприятие" одной из самых часто используемых коллекций данных является ТаблицаЗначений. Она позволяет хранить информацию в двумерном виде (строки и колонки) и выполнять над ней различные аналитические и математические операции. Одной из ключевых операций является группировка строк с одновременным суммированием числовых показателей. За эту функциональность отвечает встроенный метод Свернуть().
Однако начинающие разработчики часто сталкиваются с ошибками времени выполнения при попытке применить этот метод. В этой статье мы подробно разберем типичную синтаксическую и логическую ошибку, из-за которой система выдает предупреждение, выясним причины её возникновения и рассмотрим лучшие практики безопасной работы с методом Свернуть().
Рассмотрим исходный фрагмент кода, который вызвал затруднения у автора темы на форуме:
Таб = Новый ТаблицаЗначений;
Таб.Колонки.Добавить("Товар");
Для Каждого СтрокаПартииРаспределения ИЗ СтрокаДереваПартий.Строки Цикл
Стр = Таб.Добавить();
Стр.Товар = СтрокаПартииРаспределения.Номенклатура;
КонецЦикла;
Стр.Свернуть("Товар",);
В данном примере мы видим несколько критических ошибок, которые приводят к неработоспособности алгоритма. Разберем их пошагово.
Стр инициализируется внутри цикла Для Каждого как результат метода Добавить(). Соответственно, тип этой переменной — СтрокаТаблицыЗначений. Метод Свернуть() предназначен для работы со всей коллекцией данных в целом, поэтому он принадлежит исключительно объекту ТаблицаЗначений. Попытка вызвать его у строки таблицы приводит к ошибке: "Метод объекта не обнаружен (Свернуть)".Стр.Свернуть("Товар",); после первого параметра установлена запятая, при этом второй параметр (колонки суммирования) оставлен пустым. Хотя платформа 1С лояльно относится к опущенным необязательным параметрам в некоторых методах, оставлять висящую запятую в самом конце вызова без последующих аргументов — плохая практика, которая в ряде режимов совместимости может вызывать синтаксические предупреждения конфигуратора.Стр определяется внутри цикла. После завершения цикла в ней остается ссылка на самую последнюю добавленную строку таблицы. Сворачивать одну конкретную (последнюю) строку не имеет никакого физического смысла.Для того чтобы исправить код и успешно сгруппировать данные по товарам, нам необходимо вызвать метод Свернуть() непосредственно у самого объекта таблицы значений, который хранится в переменной Таб. Также избавимся от лишней запятой в параметрах метода.
Скорректированный рабочий вариант кода будет выглядеть следующим образом:
Таб = Новый ТаблицаЗначений;
Таб.Колонки.Добавить("Товар");
Для Каждого СтрокаПартииРаспределения ИЗ СтрокаДереваПартий.Строки Цикл
Стр = Таб.Добавить();
Стр.Товар = СтрокаПартииРаспределения.Номенклатура;
КонецЦикла;
// Правильный вызов метода у объекта ТаблицаЗначений
Таб.Свернуть("Товар");
После выполнения этого кода в таблице значений Таб останутся только уникальные строки с товарами, а все дублирующиеся элементы будут удалены.
Использование метода Свернуть() кажется простым, но в реальной практике разработки существует множество неочевидных ловушек. Проанализируем ключевые особенности этого инструмента, о которых должен знать каждый разработчик.
Самая распространенная ошибка при работе с этим методом — потеря данных. Метод Свернуть() полностью перестраивает структуру таблицы "на лету". Те колонки, названия которых не были явно указаны в первом параметре (колонки группировки) или во втором параметре (колонки суммирования), будут удалены из таблицы значений навсегда вместе со всеми содержащимися в них данными.
Рассмотрим эту ситуацию на примере:
Таб = Новый ТаблицаЗначений;
Таб.Колонки.Добавить("Товар");
Таб.Колонки.Добавить("Склад");
Таб.Колонки.Добавить("Количество");
// Заполняем таблицу данными...
// ...
// Мы хотим сгруппировать таблицу по товарам
Таб.Свернуть("Товар");
После выполнения строки Таб.Свернуть("Товар"); из таблицы значений полностью исчезнут колонки "Склад" и "Количество". Если нам требуется сохранить данные, мы обязаны указать их в параметрах. Например, если склад нужно оставить в группировке, а количество — просуммировать:
Таб.Свернуть("Товар, Склад", "Количество");
Второй параметр метода принимает список колонок, значения которых необходимо сложить. Платформа накладывает жесткие требования на типы данных в этих колонках:
Число, операция пройдет успешно.0.Списки колонок группировки (первый параметр) и колонок суммирования (второй параметр) ни при каких обстоятельствах не должны пересекаться. Вы не можете одновременно группировать по одной и той же колонке и суммировать её.
Если написать код следующим образом:
Таб.Свернуть("Товар, Количество", "Количество");
Платформа 1С незамедлительно вызовет ошибку времени выполнения: "Списки колонок не должны пересекаться". Всегда тщательно разделяйте аналитические разрезы и суммируемые показатели.
Объект ТаблицаЗначений является исключительно серверным типом данных. Он не существует на тонком клиенте и в веб-клиенте. Соответственно, производить любые манипуляции с этим объектом, включая вызов метода Свернуть(), непосредственно в клиентском коде (в процедурах с директивой выполнения &НаКлиенте) невозможно. Это вызовет синтаксическую ошибку еще на этапе компиляции модуля.
Если вам необходимо свернуть таблицу, полученную на клиенте (например, данные формы), необходимо передать эти данные на сервер, выполнить свертку в серверном контексте и вернуть результат обратно. Посмотрим, как это реализуется на практике:
&НаКлиенте
Процедура ОбработатьДанныеФормы()
// Передаем управление на сервер для работы с таблицей значений
СвернутьТаблицуНаСервере();
КонецПроцедуры
&НаСервере
Процедура СвернутьТаблицуНаСервере()
// Конвертируем данные формы в таблицу значений
Таб = РеквизитФормыВЗначение("Объект.Товары", Тип("ТаблицаЗначений"));
// Сворачиваем таблицу на сервере
Таб.Свернуть("Товар", "Количество");
// Возвращаем измененную таблицу обратно в данные формы
ЗначениеВРеквизитФормы(Таб, "Объект.Товары");
КонецПроцедуры
У объектов метаданных (например, у документов или справочников) есть табличные части, которые в коде представляются типом ТабличнаяЧасть. Этот тип также обладает методом Свернуть(), но логика его работы существенно отличается от поведения одноименного метода у ТаблицыЗначений.
Главные отличия заключаются в следующем:
Свернуть() у табличной части не может удалить колонки физически. Структура колонок всегда остается неизменной.Понимание этих базовых различий убережет вас от трудноотслеживаемых ошибок при работе с данными документов напрямую без выгрузки в промежуточные таблицы значений.