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

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

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

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

Анализ проблемы и ошибочных попыток ее решения

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


Отчет = ПолучитьОбъектОтчета("СебестоимостьКомиссионера");   
Отчет.УстановитьНачальныеНастройки(); 
    
Отчет.УниверсальныйОтчет.ДатаНач = Дата(1, 1, 1);
Отчет.УниверсальныйОтчет.ДатаКон = ДатаК;  
Отчет.УниверсальныйОтчет.ВыводитьОбщиеИтоги = Ложь; 
// Добавление показателей и полей...
Отчет.УниверсальныйОтчет.ДобавитьПоказатель(...);
Отчет.УниверсальныйОтчет.ДобавитьДополнительноеПоле(...);

Результат = Отчет.УниверсальныйОтчет.ПолучитьРезультат();

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

Попытки исправить ситуацию установкой свойства построителя:

Отчет.УниверсальныйОтчет.ПостроительОтчета.ВыводитьОбщиеИтоги = Ложь;

или попытки воздействовать через свойства компоновки данных:


Элемент = Отчет.УниверсальныйОтчет.КомпоновщикНастроек.Настройки.ПараметрыВывода.Элементы.Найти("ГоризонтальноеРасположениеОбщихИтогов");
Элемент.Значение = РасположениеИтоговКомпоновкиДанных.Нет;

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

Причины поведения платформы 1С:Предприятие

  1. Область действия свойства ВыводитьОбщиеИтоги. Свойства ПостроительОтчета.ВыводитьОбщиеИтоги и УниверсальныйОтчет.ВыводитьОбщиеИтоги отвечают исключительно за визуальное формирование отчета в ТабличныйДокумент при вызове методов Вывести() или СформироватьОтчет(). На этап исполнения запроса в СУБД и на объект РезультатЗапроса эти флаги не оказывают никакого влияния.
  2. Специфика синтаксиса расширения языка запросов для построителя отчета. В построителе отчета секция расчета итогов является управляемой только тогда, когда она заключена в фигурные скобки: {ИТОГИ ПО ОБЩИЕ}. Если же разработчик отчета в исходном тексте запроса жестко прописал директиву ИТОГИ ПО ОБЩИЕ без фигурных скобок, платформа в обязательном порядке рассчитывает общий итог на уровне SQL-запроса, игнорируя любые программные настройки группировок.
  3. Механизм выгрузки результата запроса в плоскую таблицу. Метод РезультатЗапроса.Выгрузить() по умолчанию использует прямой обход данных (ОбходРезультатаЗапроса.Прямой). Если в запросе присутствует инструкция ИТОГИ ПО ОБЩИЕ, платформа всегда помещает строку с общими итогами на самую первую позицию (индекс 0).
  4. Неприменимость СКД к построителю отчета. Классический универсальный отчет построен на базе ПостроительОтчета. Изменение параметров в КомпоновщикНастроек бесполезно, поскольку механизм Системы компоновки данных в данном отчете для построения результата не задействован.

Способ 1. Исправление текста запроса построителя отчета

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


// Было в тексте запроса:
ИТОГИ ПО
    ОБЩИЕ

// Следует изменить на расширение языка:
{ИТОГИ ПО
    ОБЩИЕ}

Если конфигурация находится на поддержке без возможности изменения, можно модифицировать текст запроса непосредственно в коде перед получением результата:


ТекстЗапроса = Отчет.УниверсальныйОтчет.ПостроительОтчета.Текст;
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ИТОГИ ПО ОБЩИЕ", "{ИТОГИ ПО ОБЩИЕ}");
Отчет.УниверсальныйОтчет.ПостроительОтчета.Текст = ТекстЗапроса;

Результат = Отчет.УниверсальныйОтчет.ПолучитьРезультат();

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

Способ 2. Программное удаление строки итогов из готовой таблицы

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


Результат = Отчет.УниверсальныйОтчет.ПолучитьРезультат();

Если Результат.Количество() > 0 Тогда
    Результат.Удалить(0);
КонецЕсли;

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

Способ 3. Прямая выборка только детальных записей

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


// Инициализируем построитель отчета и выполняем запрос
Отчет.УниверсальныйОтчет.ПостроительОтчета.Выполнить();
РезультатЗапроса = Отчет.УниверсальныйОтчет.ПостроительОтчета.Результат;

// Создаем пустую таблицу нужной структуры
ТаблицаРезультат = РезультатЗапроса.Выгрузить();
ТаблицаРезультат.Очистить();

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

Такой подход защищает логику алгоритма от случайного попадания любых итоговых строк в результирующий набор данных.

Способ 4. Получение чистого объекта Запрос из построителя

Построитель отчета формирует готовый исполняемый запрос с учетом всех установленных условий, полей и отборов. Мы можем перехватить сгенерированный объект Запрос, очистить его текст от секции итогов и выполнить напрямую:


Запрос = Отчет.УниверсальныйОтчет.ПостроительОтчета.ПолучитьЗапрос();

// Удаляем конструкцию итогов из текста запроса
ПозицияИтогов = Найти(ВРег(Запрос.Текст), "ИТОГИ");
Если ПозицияИтогов > 0 Тогда
    Запрос.Текст = Лев(Запрос.Текст, ПозицияИтогов - 1);
КонецЕсли;

Результат = Запрос.Выполнить().Выгрузить();

Этот вариант исключает лишнюю нагрузку на СУБД по подсчету ненужных общих сумм и сразу возвращает чистую плоскую таблицу без строки итогов.

← На главную