Как программно получить общие итоги отчета на СКД без повторного выполнения запроса?

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

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

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

Вывод результата СКД в коллекцию значений

Один из самых очевидных способов получить доступ к данным отчета до или после его вывода в табличный документ — это выгрузить результат в коллекцию значений, например, в ТаблицаЗначений или ДеревоЗначений. Посмотрим на пример кода, который выводит результат сначала в таблицу, а затем в документ:


КомпоновщикМакет = Новый КомпоновщикМакетаКомпоновкиДанных;
Макет = КомпоновщикМакет.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.Настройки, ДанныеРасшифровки);

ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(Макет, , ДанныеРасшифровки);

// Вывод в таблицу значений
ПроцессорВыводаТЗ = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
ТЗСРезультатом = Новый ТаблицаЗначений;
ПроцессорВыводаТЗ.УстановитьОбъект(ТЗСРезультатом);
ПроцессорВыводаТЗ.Вывести(ПроцессорКомпоновки);

Однако при таком подходе мы сталкиваемся с несколькими проблемами. Во-первых, для вывода в коллекцию необходимо использовать специальный генератор макета: ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений. Во-вторых, чтобы получить именно общие итоги удобным способом, результат лучше выгружать в ДеревоЗначений. В корневой строке дерева (с индексом 0) как раз и будут содержаться общие итоги.

Главный минус этого метода — проблема двойного построения. Основные затраты ресурсов приходятся на метод Инициализировать объекта ПроцессорКомпоновкиДанных. Данные в процессоре компоновки представляют собой однонаправленный поток. Если мы один раз прочитали его с помощью ПроцессорВывода.Вывести(), то для вывода в табличный документ придется заново инициализировать процессор, что приведет к повторному запросу к БД. Выясним причину: СКД не хранит сформированный результат в оперативной памяти целиком, а отдает его порциями.

Оптимальный способ: Перехват данных в цикле вывода

Чтобы избежать двойного запроса к БД и потери быстродействия, проанализируем ситуацию с точки зрения поэлементного вывода. Вместо того чтобы сразу "выбрасывать" весь результат в документ одной командой, мы можем выводить его в цикле, анализируя каждый элемент "на лету".

Разберем по шагам алгоритм ручного вывода:

  1. Инициализируем ПроцессорКомпоновкиДанных.
  2. Инициализируем ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент и вызываем у него метод НачатьВывод().
  3. Используем метод ПроцессорКомпоновки.Следующий() в цикле.
  4. На каждой итерации анализируем полученный ЭлементРезультатаКомпоновкиДанных.
  5. Передаем элемент в документ методом ПроцессорВывода.ВывестиЭлемент().
  6. Завершаем вывод методом ЗакончитьВывод().

Посмотрим на пример кода, реализующий этот подход:


ПроцессорВывода.НачатьВывод();
ЕстьДанные = Ложь;

Пока Истина Цикл
    ЭлементРезультата = ПроцессорКомпоновки.Следующий();
    Если ЭлементРезультата = Неопределено Тогда
        Прервать;
    КонецЕсли;
    
    // Проверяем наличие хоть каких-то данных
    Если ЭлементРезультата.ТипЭлемента = ТипЭлементаРезультатаКомпоновкиДанных.ДетальнаяЗапись 
         Или ЭлементРезультата.ТипЭлемента = ТипЭлементаРезультатаКомпоновкиДанных.НачалоГруппировки Тогда
        ЕстьДанные = Истина;
    КонецЕсли;
    
    // Здесь можно анализировать значения параметров (итогов)
    Если ЭлементРезультата.ЗначенияПараметров.Количество() > 0 Тогда
        // Логика поиска нужного ресурса
    КонецЕсли;

    ПроцессорВывода.ВывестиЭлемент(ЭлементРезультата);
КонецЦикла;

ПроцессорВывода.ЗакончитьВывод();

Этот метод позволяет за один проход получить и заполненный табличный документ, и нужные итоги (или флаг наличия данных). Он работает максимально быстро и не нагружает сервер повторными вычислениями.

Использование внешних функций в СКД

Существует еще один изящный способ получения итогов. Мы можем определить экспортную функцию в общем модуле и вызвать её прямо в вычисляемых полях или ресурсах схемы компоновки данных.

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

Поиск через именованные области табличного документа

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

Более надежный путь: задать фиксированное "Имя" ячейке ресурса на вкладке Макеты в схеме СКД. После выполнения ПроцессорВывода.Вывести() мы можем обратиться к документу и прочитать значение ячейки по программно назначенному имени области. Это работает моментально и не требует сложных обходов в цикле.

Итоги

Если вам нужно узнать только факт наличия данных, быстрее всего добавить системное поле Количество() и перехватить его в цикле через ПроцессорКомпоновки.Следующий(). Если вам нужны конкретные цифры общих итогов, и вы не хотите использовать двойное выполнение запроса — используйте цикл с проверкой ЭлементРезультатаКомпоновкиДанных или вызов экспортных функций напрямую из ресурсов СКД. Оба этих подхода демонстрируют профессиональное владение платформой 1С и обеспечивают максимальное быстродействие ваших отчетов.

← На главную