Как в отчете СКД настроить выборочный вывод строк табличной части в зависимости от условий

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

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

Постановка задачи и анализ ситуации

Разберем конкретную ситуацию: имеется документ Журнал9 с табличной частью Услуги. Нам необходимо построить отчет со следующими правилами вывода:

  1. Если в табличной части есть услуги, у которых флаг Исполнено установлен в значение Истина, то отчет должен вывести все такие строки.
  2. Если в табличной части нет ни одной исполненной услуги, отчет должен вывести только одну строку — самую первую (с минимальным номером строки).
  3. Если документ имеет признак Закрыто, то услуги выводить не нужно вовсе, либо выводить только общие данные заголовка (например, вид договора).

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

Способ 1. Использование временных таблиц для анализа состояния документа

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


ВЫБРАТЬ
    Журнал.Ссылка КАК Ссылка,
    МАКСИМУМ(ЖурналУслуги.Исполнено) КАК ЕстьИсполненные
ПОМЕСТИТЬ ВтСостояниеИсполнения
ИЗ
    Документ.Журнал9 КАК Журнал
ЛЕВОЕ СОЕДИНЕНИЕ Документ.Журнал9.Услуги КАК ЖурналУслуги
    ПО Журнал.Ссылка = ЖурналУслуги.Ссылка
ГДЕ
    Журнал.Дата МЕЖДУ &НачалоПериода И &КонецПериода
СГРУППИРОВАТЬ ПО
    Журнал.Ссылка;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    Журнал.Ссылка КАК Ссылка,
    Журнал.ВидДоговора1,
    ЖурналУслуги.Номенклатура,
    ЖурналУслуги.Исполнено
ИЗ
    Документ.Журнал9 КАК Журнал
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВтСостояниеИсполнения КАК Состояние
    ПО Журнал.Ссылка = Состояние.Ссылка
ЛЕВОЕ СОЕДИНЕНИЕ Документ.Журнал9.Услуги КАК ЖурналУслуги
    ПО Журнал.Ссылка = ЖурналУслуги.Ссылка
ГДЕ
    ВЫБОР
        КОГДА Состояние.ЕстьИсполненные ТОГДА
            ЖурналУслуги.Исполнено = ИСТИНА
        ИНАЧЕ
            ЖурналУслуги.НомерСтроки = 1
    КОНЕЦ

Проанализируем, как работает этот код. В первой временной таблице ВтСостояниеИсполнения мы определяем «статус» документа в контексте отчета. Функция МАКСИМУМ(Исполнено) для булевого поля вернет Истина, если хотя бы в одной строке стоит галка. Во втором запросе мы используем конструкцию ВЫБОР в секции ГДЕ. Это позволяет динамически менять условие фильтрации для каждой строки в зависимости от данных заголовка, полученных из временной таблицы.

Способ 2. Обработка закрытых документов через ОБЪЕДИНИТЬ ВСЕ

Если условие становится еще сложнее (например, для закрытых документов вообще не нужно лезть в табличную часть), можно применить оператор ОБЪЕДИНИТЬ ВСЕ. Это разделит выборку на два независимых потока данных. Выясним, как это выглядит в коде:


// Часть 1: Выбираем только закрытые документы (без детализации по услугам)
ВЫБРАТЬ
    Журнал9.Ссылка,
    Журнал9.Дата,
    Журнал9.ВидДоговора1,
    NULL КАК Номенклатура,
    Журнал9.Закрыто
ИЗ
    Документ.Журнал9 КАК Журнал9
ГДЕ
    Журнал9.Дата МЕЖДУ &НачалоПериода И &КонецПериода
    И Журнал9.Закрыто = ИСТИНА

ОБЪЕДИНИТЬ ВСЕ

// Часть 2: Выбираем услуги для открытых документов по сложной логике
ВЫБРАТЬ
    Журнал9Услуги.Ссылка,
    Журнал9Услуги.Ссылка.Дата,
    Журнал9Услуги.Ссылка.ВидДоговора1,
    Журнал9Услуги.Номенклатура,
    ЛОЖЬ
ИЗ
    Документ.Журнал9.Услуги КАК Журнал9Услуги
ГДЕ
    Журнал9Услуги.Ссылка.Дата МЕЖДУ &НачалоПериода И &КонецПериода
    И Журнал9Услуги.Ссылка.Закрыто = ЛОЖЬ
    И (Журнал9Услуги.Исполнено = ИСТИНА ИЛИ Журнал9Услуги.НомерСтроки = 1)

Важный момент: при использовании ОБЪЕДИНИТЬ ВСЕ необходимо следить за идентичностью колонок в обоих запросах. Обратите внимание, что во второй части мы обращаемся к реквизитам через точку (Журнал9Услуги.Ссылка.Дата). В реальных задачах для оптимизации лучше сначала выбрать ссылки нужных документов во временную таблицу, а затем соединяться с ними, чтобы избежать многократного обращения к таблице ссылочного типа через точку.

Способ 3. Тонкая настройка через механизмы СКД

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

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

Еще один профессиональный прием — использование системного поля НомерВГруппе. Посмотрим, как это настроить:

  1. В структуре отчета создадим группировку по документу (Ссылка).
  2. Внутри нее добавим группировку «Детальные записи» (наши услуги).
  3. Для группировки «Детальные записи» на закладке «Отбор» добавим условие: СистемныеПоля.НомерВГруппе Равно 1.

Это заставит СКД выводить только одну первую строку для каждого документа. Чтобы это работало только при отсутствии исполненных услуг, условие отбора можно сделать составным, используя Группу ИЛИ в настройках отбора компоновки.

Оптимизация и контроль дублей

При работе с табличными частями в СКД часто возникает проблема дублирования сумм заголовка (например, СуммаДокумента суммируется столько раз, сколько строк вывелось в отчет). Чтобы этого избежать, обязательно заглянем на закладку «Наборы данных» и настроим Роли полей.

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

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

← На главную