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