Почему Построитель отчета не видит параметры в фигурных скобках и как это исправить?

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

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

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

Выясняем причину: почему Построитель отчета «игнорирует» фигурные скобки?

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


РегистрБухгалтерии.РегистрБухгалтерииОсновной.Обороты({(&НачалоПериода)}, {(&КонецПериода)}, , , , , , ) КАК Основной

Синтаксис вида {(&Параметр)} внутри параметров виртуальных таблиц — это расширение языка запросов, разработанное исключительно для Системы компоновки данных (СКД). Когда СКД видит такую конструкцию, она динамически управляет обязательностью параметра. Если пользователь не заполнил дату начала или окончания периода, СКД на лету удаляет этот параметр из итогового SQL-запроса к СУБД, и данные выбираются за весь период.

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

  1. {ВЫБРАТЬ ...} — определяет поля, которые пользователь может выбрать для вывода в отчет.
  2. {ГДЕ ...} — задает необязательные условия отбора, которые накладываются на результат запроса.
  3. {УПОРЯДОЧИТЬ ПО ...} — описывает доступные поля для сортировки данных.
  4. {ИТОГИ ПО ...} — задает возможные группировки и настройки расчета итогов.

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

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

---

Разберем по шагам альтернативные варианты решения проблемы

Если по каким-то причинам вы не можете перевести отчет на СКД (например, отчет жестко интегрирован в старую конфигурацию на обычных формах с использованием специфического макета), проблему можно решить программными методами в коде 1С.

Вариант 1. Динамическое формирование текста запроса (Рекомендуемый)

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

Рассмотрим пример реализации этого подхода:


// 1. Создаем базовый шаблон запроса с подстановкой
ТекстЗапроса = 
    "ВЫБРАТЬ
    |    Основной.Счет.СчетDE КАК Счет,
    |    Основной.СуммаОборот КАК Сумма
    |ИЗ
    |    РегистрБухгалтерии.РегистрБухгалтерииОсновной.Обороты(&ПараметрыПериода) КАК Основной
    |ИТОГИ
    |    СУММА(Сумма)
    |ПО
    |    ОБЩИЕ,
    |    Счет";

// 2. Анализируем заполнение дат и формируем строку параметров виртуальной таблицы
СтрокаПараметров = "";
Если ЗначениеЗаполнено(НачалоПериода) И ЗначениеЗаполнено(КонецПериода) Тогда
    СтрокаПараметров = "&НачалоПериода, &КонецПериода";
    Построитель.Параметры.Вставить("НачалоПериода", НачалоПериода);
    Построитель.Параметры.Вставить("КонецПериода", КонецДня(КонецПериода));
ИначеЕсли ЗначениеЗаполнено(НачалоПериода) Тогда
    СтрокаПараметров = "&НачалоПериода, ";
    Построитель.Параметры.Вставить("НачалоПериода", НачалоПериода);
ИначеЕсли ЗначениеЗаполнено(КонецПериода) Тогда
    СтрокаПараметров = ", &КонецПериода";
    Построитель.Параметры.Вставить("КонецПериода", КонецДня(КонецПериода));
Иначе
    // Если обе даты пустые, параметры в скобках вообще не указываем
    СтрокаПараметров = ", ";
КонецЕсли;

// 3. Подставляем сформированную строку в текст запроса
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПараметрыПериода", СтрокаПараметров);

// 4. Передаем готовый текст Построителю отчета
Построитель.Текст = ТекстЗапроса;
Построитель.ЗаполнитьНастройки();
Построитель.Выполнить();

Этот способ является наиболее производительным и надежным, так как в СУБД уходит максимально чистый и оптимизированный SQL-запрос.

Вариант 2. Использование граничных (экстремальных) дат

Если вы не хотите динамически менять текст запроса и предпочитаете оставить параметры жестко прописанными (без фигурных скобок), можно программно обрабатывать ситуации, когда пользователь не заполнил периоды. В таком случае мы будем передавать в параметры "экстремальные" значения дат.

Посмотрим, как выглядит программная реализация:


Построитель.Текст = 
    "ВЫБРАТЬ
    |    Основной.Счет.СчетDE КАК Счет,
    |    Основной.СуммаОборот КАК Сумма
    |ИЗ
    |    РегистрБухгалтерии.РегистрБухгалтерииОсновной.Обороты(&НачалоПериода, &КонецПериода) КАК Основной
    |ИТОГИ
    |    СУММА(Сумма)
    |ПО
    |    ОБЩИЕ,
    |    Счет";

// Проверяем заполнение дат. Если пустые — подставляем минимальное и максимальное значения
РабочееНачалоПериода = ?(ЗначениеЗаполнено(НачалоПериода), НачалоПериода, Дата(1, 1, 1));
РабочийКонецПериода  = ?(ЗначениеЗаполнено(КонецПериода), КонецДня(КонецПериода), Дата(3999, 12, 31, 23, 59, 59));

Построитель.Параметры.Вставить("НачалоПериода", РабочееНачалоПериода);
Построитель.Параметры.Вставить("КонецПериода", РабочийКонецПериода);

Построитель.ЗаполнитьНастройки();
Построитель.Выполнить();

Этот подход избавляет от необходимости манипуляций со строками, однако имеет небольшой нюанс: СУБД все равно будет применять условия фильтрации по датам на уровне индексов, хотя фактически будет выбираться весь диапазон данных. На производительность современных СУБД это практически не влияет.

Вариант 3. Фильтрация через секцию ГДЕ (Не рекомендуется!)

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

Проанализируем этот пример запроса:


Построитель.Текст = 
    "ВЫБРАТЬ
    |    Основной.Счет.СчетDE КАК Счет,
    |    Основной.СуммаОборот КАК Сумма
    |ИЗ
    |    РегистрБухгалтерии.РегистрБухгалтерииОсновной.Обороты(, , , , , , , ) КАК Основной
    |{ГДЕ
    |    (Основной.Период >= &НачалоПериода),
    |    (Основной.Период <= &КонецПериода)}
    |ИТОГИ
    |    СУММА(Сумма)
    |ПО
    |    ОБЩИЕ,
    |    Счет";

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

---

Как аналогичная задача решается в СКД?

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

При использовании СКД вам достаточно написать следующий запрос:


ВЫБРАТЬ
    Основной.Счет.СчетDE КАК Счет,
    Основной.СуммаОборот КАК Сумма
ИЗ
    РегистрБухгалтерии.РегистрБухгалтерииОсновной.Обороты({(&НачалоПериода)}, {(&КонецПериода)}) КАК Основной

В СКД фигурные скобки { } вокруг параметров виртуальной таблицы указывают системе, что эти параметры являются необязательными для СКД. Компоновщик макета СКД анализирует настройки отчета и, если параметры не заполнены или отключены пользователем, автоматически удаляет их из текста итогового SQL-запроса, формируя оптимальное обращение к базе данных без участия разработчика.

← На главную