Как правильно вывести результат сложного запроса в отчет 1С

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

При разработке отчетов в системе «1С:Предприятие» программисты часто сталкиваются с дилеммой: использовать Систему компоновки данных (СКД) или формировать отчет программно с использованием макета. Программный вывод дает больше гибкости в оформлении, но требует строгого соблюдения логики обхода выборки и работы с областями табличного документа. Разберем подробно, как поместить данные запроса в отчет, исправить типичные ошибки группировки и оптимизировать работу с виртуальными таблицами.

Анализ типичных ошибок ручного вывода

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

  1. Вывод области вне цикла: Если метод ТабДок.Вывести(ОбластьСтрока) расположен после завершения цикла Пока Выборка.Следующий(), в отчет попадет только последняя запись из результата запроса.
  2. Отсутствие очистки параметров: При использовании одной и той же области макета в цикле, значения параметров «кэшируются». Если для новой строки значение не задано явно, будет выведено значение из предыдущей итерации.
  3. Неправильная логика группировки: Если в запросе данные приходят в разрезе «День — Категория клиента», то при обычном обходе на один день будет создано столько строк, сколько было категорий. Для решения этой проблемы нужно либо использовать вложенные циклы, либо метод Присоединить() для горизонтального вывода.

Оптимизация запроса для отчета

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

Вместо такого кода:


|ИЗ
| РегистрНакопления.Работа.Обороты(&Дата1, &Дата2, ДЕНЬ, ) КАК РаботаОбороты
|ГДЕ
| РаботаОбороты.Продавец = &Продавец

Следует использовать правильную конструкцию:


|ИЗ
| РегистрНакопления.Работа.Обороты(&Дата1, &Дата2, ДЕНЬ, Продавец = &Продавец) КАК РаботаОбороты

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

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


Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
    // Отключаем стандартный вывод СКД
    СтандартнаяОбработка = Ложь;
    ДокументРезультат.Очистить();

    // Получаем настройки и параметры отчета
    Настройки = КомпоновщикНастроек.ПолучитьНастройки();
    ПараметрПериод = Настройки.ПараметрыДанных.Элементы.Найти("Период").Значение;
    Продавец = Настройки.ПараметрыДанных.Элементы.Найти("Продавец").Значение;

    // Вызываем функцию формирования
    СформироватьОтчет(ДокументРезультат, ПараметрПериод.ДатаНачала, ПараметрПериод.ДатаОкончания, Продавец);
КонецПроцедуры

Алгоритм обхода выборки с группировкой по дням

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


Функция СформироватьОтчет(ТабДок, Дата1, Дата2, Продавец)
    Запрос = Новый Запрос;
    Запрос.Текст = 
    "ВЫБРАТЬ
    |	РаботаОбороты.Период КАК Период,
    |	РаботаОбороты.КатегорияКлиента КАК КатегорияКлиента,
    |	РаботаОбороты.КоличествоУслугОборот КАК КолУслуг
    |ИЗ
    |	РегистрНакопления.Работа.Обороты(&Дата1, &Дата2, ДЕНЬ, Продавец = &Продавец) КАК РаботаОбороты
    |УПОРЯДОЧИТЬ ПО
    |	Период";

    Запрос.УстановитьПараметр("Дата1", НачалоДня(Дата1));
    Запрос.УстановитьПараметр("Дата2", КонецДня(Дата2));
    Запрос.УстановитьПараметр("Продавец", Продавец);

    Выборка = Запрос.Выполнить().Выбрать();
    
    Макет = ПолучитьМакет("МакетОтчета");
    ОбластьШапка = Макет.ПолучитьОбласть("Шапка");
    ОбластьДень  = Макет.ПолучитьОбласть("ЗаголовокДня");
    ОбластьСтрока = Макет.ПолучитьОбласть("Строка");
    
    ТабДок.Вывести(ОбластьШапка);
    
    ТекущийДень = Неопределено;
    
    Пока Выборка.Следующий() Цикл
        // Проверяем, наступил ли новый день в выборке
        Если ТекущийДень <> Выборка.Период Тогда
            ТекущийДень = Выборка.Период;
            ОбластьДень.Параметры.ДатаДня = Формат(ТекущийДень, "ДЛФ=D");
            ТабДок.Вывести(ОбластьДень);
        КонецЕсли;

        // Заполняем данные конкретной категории клиента
        ОбластьСтрока.Параметры.Заполнить(Выборка);
        ТабДок.Вывести(ОбластьСтрока);
    КонецЦикла;
КонецФункции

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

Если задача требует вывести категории клиентов не строками, а колонками (создать кросс-таблицу вручную), проанализируем использование метода Присоединить(). В макете необходимо создать вертикальную область (например, «КолонкаКатегории»).

Рассмотрим алгоритм действий:

  1. Выводим левую фиксированную часть строки (например, время или номер) через ТабДок.Вывести(ОбластьЛеваяЧасть).
  2. В цикле по категориям (которые можно получить вложенным запросом или предварительной выгрузкой в таблицу значений) подготавливаем область колонки.
  3. Используем ТабДок.Присоединить(ОбластьКолонка). Это «приклеит» новую секцию справа к уже выведенной строке.

Важные замечания по работе с ресурсами

Проанализируем ситуацию с суммированием итогов. Чтобы не писать громоздкий код суммирования в цикле (например, Итого = Итого + Выборка.Сумма), рекомендуется использовать возможности языка запросов 1С. Предложение ИТОГИ СУММА(...) ПО ОБЩИЕ, Период позволит вам получить иерархическую выборку. При обходе такой выборки методом Выборка.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам) вы сначала получите общие итоги, затем итоги по дням, и только внутри — детальные записи.

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

← На главную