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

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

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

В этой статье мы подробно разберем, почему возникает популярная ошибка "Метод объекта не обнаружен", как правильно обходить коллекции строк, и рассмотрим несколько вариантов решения задачи заполнения таблиц — от простых циклов до профессионального использования запросов и оптимизации алгоритмов по принципу DRY (Don't Repeat Yourself).

Выясняем причину ошибки: почему возникает «Метод объекта не обнаружен»?

Рассмотрим исходную проблему. Разработчик пытался проверить наличие данных в колонке ОтданыНаПовторы для четырех таблиц с помощью следующего условия:


Если ТаблицаСборки.ОтданыНаПовторы Или ТаблицаПСИ.ОтданыНаПовторы Или ТаблицаОкончательнойСборки.ОтданыНаПовторы ... Тогда

При выполнении этого кода система выдает ошибку: Метод объекта не обнаружен (ОтданыНаПовторы). Давайте разберемся, почему это происходит.

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

---

Решение 1. Построчный обход таблиц с фильтрацией (Простой вариант)

Самое первое и очевидное решение — это добавить условие фильтрации непосредственно внутрь цикла обхода строк каждой таблицы. Если числовое значение в колонке ОтданыНаПовторы больше нуля, мы добавляем новую строку в результирующую таблицу ТаблицаПовторов и заполняем её данными.

Рассмотрим, как будет выглядеть код для одной из таблиц:


Для Каждого Стр Из ТаблицаСборки Цикл
    // Проверяем значение в конкретной строке текущего шага цикла
    Если Стр.ОтданыНаПовторы > 0 Тогда
        НоваяСтрока = ТаблицаПовторов.Добавить();
        НоваяСтрока.ИсполняемыйПрибор = Стр.ИсполняемыйПрибор;
        НоваяСтрока.Количество = Стр.ОтданыНаПовторы;
    КонецЕсли;
КонецЦикла;

Такой подход полностью решает проблему добавления «пустых» строк. Однако, если у вас четыре разные таблицы, и вы просто скопируете этот код четыре раза для каждой из них, вы получите громоздкую процедуру с кучей дублирующегося кода.

---

Решение 2. Оптимизация с предварительной проверкой через метод Итог()

Если в табличных частях документа содержатся сотни или тысячи строк, то простой перебор всех строк во всех таблицах может выполняться неэффективно. Зачем запускать цикл обхода таблицы, если в ней вообще нет данных, требующих обработки?

Для оптимизации мы можем использовать встроенный метод табличных частей и таблиц значений — Итог(). Этот метод быстро подсчитывает сумму значений по указанной колонке без ручного обхода строк. Если сумма равна нулю, мы можем просто пропустить обработку всей таблицы.

На форуме было предложено следующее общее условие:


Если ТаблицаСборки.Иитог("ОтданыНаПовторы") > 0 
   Или ТаблицаПСИ.Итог("ОтданыНаПовторы") > 0 
   Или ТаблицаОкончательнойСборки.Итог("ОтданыНаПовторы") > 0 
   Или ТаблицаВыходногоКонтроля.Итог("ОтданыНаПовторы") > 0 Тогда
   
    // Далее идут циклы обхода всех таблиц...
КонецЕсли;

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

---

Решение 3. Архитектурно правильный подход (Обход в массиве)

Чтобы избежать дублирования одинакового кода заполнения для четырех разных таблиц (нарушение принципа DRY), мы можем применить красивый прием: поместить все таблицы-источники в массив и обработать их в одном общем цикле. Также мы добавим важную операцию — очистку результирующей таблицы перед заполнением, чтобы избежать дублирования данных при повторном нажатии кнопки.

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

Проанализируем оптимальный программный код:


Процедура ЗаполнитьПовторыНажатие(Элемент)
    
    // 1. Обязательно очищаем приемник перед новым заполнением
    ТаблицаПовторов.Очистить();
    
    // 2. Создаем массив со всеми исходными табличными частями
    СписокТаблиц = Новый Массив;
    СписокТаблиц.Добавить(ТаблицаСборки);
    СписокТаблиц.Добавить(ТаблицаПСИ);
    СписокТаблиц.Добавить(ТаблицаОкончательнойСборки);
    СписокТаблиц.Добавить(ТаблицаВыходногоКонтроля);
    
    // 3. Обходим таблицы в едином цикле
    Для Каждого ТчИсточника Из СписокТаблиц Цикл
        
        // Индивидуальная оптимизация: если в конкретной таблице нет нужных данных, пропускаем её
        Если ТчИсточника.Итог("ОтданыНаПовторы") = 0 Тогда
            Продолжить;
        КонецЕсли;
        
        // 4. Переносим строки, удовлетворяющие условию
        Для Каждого Стр Из ТчИсточника Цикл
            Если Стр.ОтданыНаПовторы > 0 Тогда
                НоваяСтрока = ТаблицаПовторов.Добавить();
                
                // Автоматически копируем реквизит "ИсполняемыйПрибор"
                ЗаполнитьЗначенияСвойств(НоваяСтрока, Стр);
                
                // Переносим количество (так как имена колонок-источников и приемника различаются)
                НоваяСтрока.Количество = Стр.ОтданыНаПовторы;
            КонецЕсли;
        КонецЦикла;
        
    КонецЦикла;

КонецПроцедуры

Этот код легко масштабировать: если у вас появится пятая или шестая таблица, вам достаточно будет просто добавить её в массив СписокТаблиц всего одной строкой кода, не переписывая алгоритм обхода.

---

Решение 4. Использование запроса (Профессиональный стандарт)

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

Запрос позволяет объединить данные нескольких табличных частей на уровне СУБД, сразу наложив фильтр по значению колонки ОтданыНаПовторы > 0, и выгрузить результат напрямую в результирующую таблицу одной командой Загрузить().

Рассмотрим пример реализации такого запроса:


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

Использование серверного запроса — это наиболее производительный и отказоустойчивый метод работы с большими объемами данных в системах на платформе 1С:Предприятие 8, исключающий лишнюю нагрузку на клиентское приложение.

← На главную