Как добавить данные в отчет на Построителе, чтобы на них не действовал общий отбор

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

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

Проанализируем ситуацию. Разработчик добавляет в запрос объединение или временную таблицу, чтобы получить данные по услугам, но стоит пользователю установить отбор Номенклатура.Вид номенклатуры НЕ РАВНО Услуга, как новая колонка обнуляется. Выясним причину такого поведения и разберем способы решения этой задачи.

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

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

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


РегистрНакопления.Продажи.Обороты(
    &ДатаНач, 
    &ДатаКон, 
    Регистратор, 
    {(Организация).* КАК Организация, (Номенклатура).* КАК Номенклатура}
) КАК ПродажиОбороты

Когда пользователь в интерфейсе устанавливает отбор по полю Номенклатура, Построитель отчета находит все вхождения этого поля внутри фигурных скобок в тексте запроса и «впрыскивает» туда соответствующее условие на языке SQL. Если в вашем запросе пять временных таблиц и в каждой из них параметры виртуальной таблицы содержат (Номенклатура).* КАК Номенклатура, отбор применится ко всем пяти таблицам без исключения.

Причина проблемы: избыточные инструкции для Построителя

Посмотрим на структуру запроса, представленного в сообщении 6. Автор добавил формирование временной таблицы втСтоимостьУслуг. Внутри этой таблицы он снова обращается к регистру Продажи.Обороты. Однако он скопировал стандартный блок параметров виртуальной таблицы вместе с фигурными скобками:


ИЗ
    РегистрНакопления.Продажи.Обороты(&ДатаНач, &ДатаКон, Регистратор, 
    {(Организация).* КАК Организация, (Проект).* КАК Проект, 
    (Номенклатура).* КАК Номенклатура, ...}) КАК ПродажиОбороты

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

Способ 1: Удаление фигурных скобок для «независимых» данных

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

Если мы хотим, чтобы на таблицу втСтоимостьУслуг вообще не действовали никакие отборы Построителя, мы должны описать обращение к регистру так:


// Вместо этого:
// РегистрНакопления.Продажи.Обороты(&ДатаНач, &ДатаКон, Регистратор, {(Номенклатура).* КАК Номенклатура})

// Пишем так:
РегистрНакопления.Продажи.Обороты(&ДатаНач, &ДатаКон, Регистратор) КАК ПродажиОбороты

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

Способ 2: Переименование псевдонимов (алиасов)

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

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

Разберем пример кода:


// В основном запросе по товарам оставляем:
{(Номенклатура).* КАК Номенклатура}

// В подзапросе по услугам пишем:
{(Номенклатура).* КАК НоменклатураДляУслуг}

После такой правки в настройках отчета (на вкладке «Отбор») появится новое доступное поле «Номенклатура для услуг». Теперь, если пользователь установит отбор по обычной Номенклатура, он подействует только на товары. А данные по услугам останутся нетронутыми, пока пользователь не решит явно отфильтровать их через новое поле.

Способ 3: Использование ГДЕ вместо параметров виртуальной таблицы

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

Построитель отчета анализирует блоки {ГДЕ ...} так же, как и параметры виртуальных таблиц в скобках. Но если вы напишете условие вне фигурных скобок, оно станет жестким и неизменным.

Сравним два варианта:

  1. Вариант с управлением: ГДЕ {(Номенклатура) КАК Номенклатура} — здесь Построитель добавит условия пользователя.
  2. Вариант без управления: ГДЕ ПродажиОбороты.Номенклатура.Услуга = ИСТИНА — это условие выполнится всегда, и Построитель не сможет его «выключить» или дополнить своими фильтрами по номенклатуре в этом конкретном месте.

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

Практические рекомендации по доработке «Валовой прибыли»

Для успешного решения задачи, описанной в теме, рекомендуем придерживаться следующего алгоритма действий:

  1. Проанализируем итоговое объединение (ОБЪЕДИНИТЬ ВСЕ) в конце запроса. Убедимся, что поле Номенклатура в ветке услуг заполнено корректно. Если там стоит ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка), как в сообщении 6, то данные по услугам никогда не попадут под отбор «Вид номенклатуры», так как у пустой ссылки нет вида номенклатуры.
  2. Если же в ветке услуг подставляется реальная ссылка на номенклатуру-услугу, необходимо проверить самый последний блок {ГДЕ ...} в тексте запроса. Часто разработчики забывают, что общие отборы могут накладываться не только на виртуальные таблицы, но и на весь результирующий набор данных.
  3. Выясним, включено ли новое поле в список доступных для отбора в настройках Построителя (свойство ДоступныеПоля). Если мы хотим скрыть внутренние механизмы от пользователя, лучше не добавлять технические поля во временных таблицах в секции фигурных скобок.

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

Таким образом, для решения проблемы автора достаточно было убрать описание полей отбора {(Номенклатура).* КАК Номенклатура...} из параметров виртуальной таблицы в блоке формирования втСтоимостьУслуг. Это разорвало бы связь между пользовательским фильтром и этим подзапросом, позволив услугам выводиться в отдельной колонке независимо от того, какой фильтр установлен на основную таблицу товаров.

← На главную