В процессе разработки отчетов на базе Системы компоновки данных (СКД) часто возникает сложная задача: необходимо скрыть не просто строку итогов по конкретному объекту (например, контрагенту или физическому лицу), но и всю ветку подчиненных ему документов, если суммарный остаток по этой ветке равен нулю. Обычный отбор на уровне детальных записей здесь не помогает, так как отдельные документы могут иметь ненулевые обороты, которые в сумме дают ноль. В этой статье мы подробно разберем, как заставить СКД анализировать итоги вышестоящих уровней для управления видимостью вложенных данных.
Рассмотрим ситуацию: у нас есть группировка ФизЛицо, а внутри нее — РасчетныйДокумент. Если мы просто установим отбор в настройках группировки ФизЛицо с условием СуммаКонечныйОстаток <> 0, система скроет заголовок группировки, но может оставить «висеть» в отчете детальные записи (документы), так как условие отбора проверяется для каждой строки отдельно. Нам же нужно, чтобы фильтр действовал иерархически: если «родитель» не прошел ценз, «дети» также не должны попадать в отчет.
Проанализируем основные способы решения этой задачи, от оптимизации запроса до тонкой настройки вычисляемых полей компоновки.
Этот метод считается наиболее производительным и «чистым» с точки зрения логики СКД. Вместо того чтобы заставлять компоновщик пересчитывать итоги и скрывать строки «на лету», мы ограничим выборку данных еще на этапе выполнения запроса к базе данных.
Разберем по шагам алгоритм реализации в тексте запроса:
ФизЛицо) и рассчитывает итоговый остаток.ГДЕ СуммаОстатка <> 0.ФизЛицо.Посмотрим на пример структуры такого запроса:
// Шаг 1: Получаем список "ненулевых" объектов
ВЫБРАТЬ
ВзаиморасчетыОстатки.ФизЛицо КАК ФизЛицо,
СУММА(ВзаиморасчетыОстатки.СуммаОстаток) КАК ИтоговыйОстаток
ПОМЕСТИТЬ ВТ_НенулевыеФизЛица
ИЗ
РегистрНакопления.Взаиморасчеты.Остатки(&Период, ) КАК ВзаиморасчетыОстатки
СГРУППИРОВАТЬ ПО
ВзаиморасчетыОстатки.ФизЛицо
ИМЕЮЩИЕ
СУММА(ВзаиморасчетыОстатки.СуммаОстаток) <> 0
;
// Шаг 2: Основная выборка детальных записей
ВЫБРАТЬ
ОсновнаяТаблица.ФизЛицо,
ОсновнаяТаблица.РасчетныйДокумент,
ОсновнаяТаблица.СуммаОстаток
ИЗ
РегистрНакопления.Взаиморасчеты.Остатки(&Период, ) КАК ОсновнаяТаблица
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_НенулевыеФизЛица КАК Фильтр
ПО ОсновнаяТаблица.ФизЛицо = Фильтр.ФизЛицо
Этот подход гарантирует, что в СКД вообще не попадут записи по тем лицам, чей общий итог равен нулю. Выясним причину, почему это удобно: вам не нужно настраивать сложные отборы в интерфейсе, и отчет будет работать быстрее на больших объемах данных.
Если по каким-то причинам вы не можете изменить запрос (например, данные собираются из нескольких наборов), воспользуемся встроенными функциями языка выражений СКД. Нам нужно «протащить» значение итога группировки на уровень детальных записей.
Рассмотрим подробнее этот механизм:
ИтогПоРодителю.ВычислитьВыражение("Сумма(СуммаКонечныйОстаток)", "ФизЛицо")
ФизЛицо и РасчетныйДокумент).В чем секрет этого метода? Функция ВычислитьВыражение с указанием конкретной группировки во втором параметре заставляет СКД вычислять агрегатную функцию в контексте указанного уровня, даже если само поле выводится в детальных записях. Теперь у каждой строки документа будет стоять значение итога по его «родителю».
После этого остается только зайти в Настройки отчета и на уровне самой верхней группировки (или всего отчета) установить отбор: ИтогПоРодителю Не равно 0. Поскольку значение итога теперь доступно везде, СКД корректно отсечет всю ветку целиком.
Еще один вариант, который часто обсуждается разработчиками: установка отбора непосредственно по ресурсу. Разберем ситуацию: у нас есть ресурс СуммаОстаток.
В настройках СКД на вкладке Настройки выберем группировку ФизЛицо. Перейдем на ее личную вкладку Отбор и добавим условие СуммаОстаток <> 0. Важно понимать, что для того, чтобы документы тоже скрылись, этот же отбор нужно продублировать и для вложенной группировки РасчетныйДокумент.
Важный нюанс: Чтобы этот метод сработал, в поле отбора нужно выбирать именно Ресурс (он помечен соответствующей иконкой), а не просто поле из набора данных. СКД при расчете итогов сначала вычислит сумму по группе, а затем применит фильтр ко всем строкам, входящим в эту группу.
При реализации сложных отборов в запросах программисты часто сталкиваются с тем, что СКД «режет» текст запроса. Вы прописываете поле в ВЫБРАТЬ, но в отчете его нет. Выясним причину этого поведения.
СКД обладает интеллектуальным механизмом оптимизации: если поле не используется в выбранных полях отчета и в нем не установлены активные отборы, система исключает его из итогового SQL-запроса для экономии ресурсов. Чтобы это предотвратить, можно пойти двумя путями:
ВЫБРАТЬ
Таблица.ФизЛицо {ПолеФизЛицо},
Таблица.Сумма {ПолеСумма}
ИЗ
Регистр КАК Таблица
ГДЕ
Таблица.Дата = &Дата {ГДЕ Таблица.ФизЛицо.*}
Если расчеты очень сложные и отборы не срабатывают так, как нужно, проанализируем «визуальный» метод. Он не удаляет данные из выборки, но делает их невидимыми для пользователя.
Посмотрим на алгоритм настройки:
Ложь.СуммаОстаток = 0.Внимание: Этот метод имеет побочный эффект — в печатной форме могут остаться пустые строки или разрывы, если отчет имеет сложную иерархию. Поэтому данный способ рекомендуется использовать только в крайних случаях, отдавая предпочтение фильтрации на уровне запроса или ресурсов.
Мы рассмотрели несколько подходов к решению задачи. Проанализируем, какой из них выбрать:
1. Если отчет строится по большим таблицам (регистры бухгалтерии, крупные регистры накопления) — используйте Способ 1 (Временные таблицы). Это обеспечит максимальную скорость работы.
2. Если структура отчета гибкая и пользователь сам должен решать, какие итоги фильтровать — используйте Способ 2 (ВычислитьВыражение). Это дает наибольшую гибкость в настройках компоновщика.
3. Всегда следите за механизмом Автозаполнения. Если ваше поле, по которому строится логика фильтрации, внезапно исчезает — проверьте настройки доступности полей в наборе данных.
Совместное использование этих техник позволит вам создавать профессиональные и удобные отчеты, в которых пользователь будет видеть только значимую информацию без «нулевого» шума.