Как в таблице значений 1С посчитать итог по колонке и удалить строки по условию?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

Расчет итога по числовой колонке таблицы

Проанализируем базовый метод расчета итога для объекта ТаблицаЗначений. Для этого в платформе 1С предусмотрен встроенный метод Итог(). Посмотрим на синтаксис его вызова:

ИтоговаяСумма = ТаблицаТовары.Итог("Сумма");

При выполнении этого метода важно учитывать несколько ключевых правил:

  1. В качестве параметра передается точное строковое имя колонки, как оно задано в структуре таблицы.
  2. Тип данных в колонке обязательно должен быть числовым (Число). Если колонка содержит строки или другие типы, подсчет итога вызовет ошибку или вернет ноль.
  3. Если обработка выполняется в контексте управляемой формы, реквизит формы является коллекцией типа ДанныеФормыКоллекция, у которой нет метода Итог(). В таком случае на сервере необходимо выполнить преобразование коллекции в полноценную таблицу значений:

Таблица = ДанныеФормыВЗначение(Объект.Товары, Тип("ТаблицаЗначений"));
ИтоговаяСумма = Таблица.Итог("Сумма");

Вывод итоговой суммы в подвал таблицы на форме

Если мы рассчитали сумму и хотим отобразить ее в нижней части таблицы (в подвале), выполним следующие настройки формы:

  1. В свойствах элемента управления (табличного поля формы) установим флаг Подвал в значение Истина. После этого под строками появится область подвала.
  2. Способ через привязку реквизита: создадим реквизит формы (например, ИтогСумма с типом Число), а в свойствах нужной колонки таблицы в поле ПутьКДаннымПодвала выберем этот реквизит. При пересчете достаточно будет присваивать значение этому реквизиту.
  3. Способ через прямое управление свойством текста: программно зададим отображаемый текст для подвала конкретной колонки:

Элементы.ТоварыСумма.ТекстПодвала = Формат(ИтоговаяСумма, "ЧДЦ=2; ЧГ=0");

Удаление строк по условию: разбор типичных ошибок

Рассмотрим распространенную ошибку прямого обхода в цикле от первого элемента к последнему:


// ОШИБОЧНЫЙ ВАРИАНТ!
Для Н = 0 По Таблица.Количество() - 1 Цикл
    Если Таблица[Н].ЕдиницаИзмерения = НужнаяСсылка Тогда
        Таблица.Удалить(Таблица[Н]);
    КонецЕсли;
КонецЦикла;

В чем заключается проблема? Когда мы удаляем строку из таблицы, все последующие строки смещаются вверх (их индексы уменьшаются на единицу). Счётчик цикла при этом переходит к следующему номеру индекса, из-за чего цикл просто перепрыгивает через строку, идущую сразу за удаленной. Кроме того, к концу цикла счетчик попытается обратиться по индексу, которого уже не существует в таблице.

Способ 1. Удаление строк с помощью метода НайтиСтроки

Наиболее лаконичный и быстрый способ поиска строк — использование встроенного метода НайтиСтроки(). Разберем его реализацию:


// 1. Формируем структуру отбора
// Имя ключа должно точно совпадать с именем колонки таблицы
СтруктураОтбора = Новый Структура("ЕдиницаИзмерения", СсылкаШт);

// 2. Получаем массив найденных строк
МассивУдаляемыхСтрок = ТаблицаТовары.НайтиСтроки(СтруктураОтбора);

// 3. Удаляем строки в цикле из таблицы
Для Каждого СтрокаТЗ Из МассивУдаляемыхСтрок Цикл
    ТаблицаТовары.Удалить(СтрокаТЗ);
КонецЦикла;

Важное замечание: Метод НайтиСтроки() выполняет строгое сравнение типов. Если колонка содержит ссылку на элемент справочника (СправочникСсылка), в структуру отбора необходимо передавать именно объектную ссылку, а не строковое значение типа "Шт".

Способ 2. Обход таблицы в обратном порядке (цикл с конца)

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


Для Индекс = ТаблицаТовары.Количество() - 1 По 0 Шаг -1 Цикл
    ТекущаяСтрока = ТаблицаТовары[Индекс];
    
    // Проверяем условие (на сервере можно обращаться через точку)
    Если ТекущаяСтрока.ЕдиницаИзмерения.Наименование = "Шт" Тогда
        ТаблицаТовары.Удалить(Индекс);
    КонецЕсли;
КонецЦикла;

Способ 3. Фильтрация через запрос (для больших объемов данных)

Когда таблица содержит тысячи строк, последовательное удаление элементов через методы таблицы может работать медленно из-за постоянного перестроения памяти. Разберем эффективный подход с использованием временных таблиц в объекте Запрос:


Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.Текст = 
    "ВЫБРАТЬ * 
    |ПОМЕСТИТЬ ВТ_Товары 
    |ИЗ &ТаблицаДанных КАК ТаблицаДанных;
    |
    |ВЫБРАТЬ * 
    |ИЗ ВТ_Товары 
    |ГДЕ ЕдиницаИзмерения <> &ИсключаемаяЕдиница";

Запрос.УстановитьПараметр("ТаблицаДанных", ИсходнаяТаблица);
Запрос.УстановитьПараметр("ИсключаемаяЕдиница", СсылкаШт);

ТаблицаТовары = Запрос.Выполнить().Выгрузить();

Этот вариант гарантирует высокую скорость обработки данных, исключает ошибки со смещением индексов и позволяет применять любые сложные логические условия в секции ГДЕ.

← На главную