Разберем типичную и крайне неприятную ситуацию, с которой часто сталкиваются разработчики при проектировании отчетов на Системе компоновки данных (СКД). Представим отчет по остаткам и резервам товаров на складах. В базе данных хранятся детальные записи, которые сами по себе не являются нулевыми (например, по одному документу зафиксирован приход 10 единиц товара, а по другому — расход -10 единиц). В сумме по группировке «Номенклатура» мы получаем чистый ноль (0).
Если мы просто наложим глобальный отбор на уровне отчета с условием Ресурс <> 0, СКД транслирует это условие в секцию ГДЕ (WHERE) SQL-запроса. Детальные записи 10 и -10 вообще не попадут в выборку. Это приведет к искажению итогов по другим группировкам или общих итогов отчета. Если же не накладывать отбор, то отчет заполнится десятками тысяч «пустых» строк с нулевыми итогами, которые сильно усложняют чтение данных пользователем.
Выясним причину этой проблемы и рассмотрим несколько эффективных способов ее решения с сохранением гибкости настроек для конечных пользователей.
---
Это самый правильный, гибкий и стандартный механизм СКД. Нам нужно наложить отбор по ресурсу не на весь отчет сразу, а внутри настроек конкретной группировки (например, группировки Номенклатура или Характеристика).
Проанализируем этот метод по шагам:
Ресурс1 Не равно 0 (или Заполнено).Ресурс1 Не равно 0 ИЛИ Ресурс2 Не равно 0.При таком подходе СКД сначала выберет все детальные записи из базы данных, корректно рассчитает по ним итоги (сложит 10 и -10), а уже на этапе вывода конкретной группировки применит фильтр. Нулевая строка скроется, но общие итоги по отчету не изменятся. Чтобы пользователь случайно не сбросил эту настройку, в свойствах элемента отбора снимем флажок Включать в пользовательские настройки.
---
Если структура отчета фиксированная, и пользователю не требуется динамически менять состав группировок или делать расшифровку до документов-регистраторов, мы можем отсечь пустые строки непосредственно в тексте запроса с помощью конструкции ИМЕЮЩИЕ (HAVING).
Посмотрим на пример такого запроса:
ВЫБРАТЬ
ВложенныйЗапрос.Измерение1 КАК Измерение1,
ВложенныйЗапрос.Измерение2 КАК Измерение2,
СУММА(ВложенныйЗапрос.Ресурс1) КАК Ресурс1,
СУММА(ВложенныйЗапрос.Ресурс2) КАК Ресурс2
ИЗ
(ВЫБРАТЬ
"Т1" КАК Измерение1,
"С1" КАК Измерение2,
10 КАК Ресурс1,
-25 КАК Ресурс2
ОБЪЕДИНИТЬ ALL
ВЫБРАТЬ
"Т1",
"С2",
-10,
25) КАК ВложенныйЗапрос
СГРУППИРОВАТЬ ПО
ВложенныйЗапрос.Измерение1,
ВложенныйЗапрос.Измерение2
ИМЕЮЩИЕ
СУММА(ВложенныйЗапрос.Ресурс1) <> 0
ИЛИ СУММА(ВложенныйЗапрос.Ресурс2) <> 0
Важное ограничение: этот способ лишает отчет универсальности. Если пользователь решит добавить в группировку новое измерение (например, СерияНоменклатуры или Регистратор), этот запрос не сможет динамически перестроиться, и на выходе мы снова можем получить пустые строки в подчиненных группировках.
---
Часто пустые строки в отчетах возникают не из-за взаимного исключения чисел, а из-за левых соединений (ЛЕВОЕ СОЕДИНЕНИЕ) таблиц в запросе. При этом измерения подчиненных таблиц принимают значения NULL, под которые СКД выделяет отдельные некрасивые пустые строки.
Чтобы решить эту проблему, выполним следующие настройки:
СерияНоменклатуры).После этого система компоновки данных перестанет создавать отдельные ветки группировок под пустые значения NULL, а просто пропустит их или свернет на уровень выше.
---
В особо сложных случаях, например, при формировании многоуровневых кросс-таблиц со сложными вычисляемыми полями, стандартные отборы СКД могут работать непредсказуемо. Тогда на помощь приходит постобработка сформированного табличного документа в модуле отчета. При необходимости можно использовать примеры программного формирования СКД и работы с макетами.
Рассмотрим алгоритм реализации этого метода по шагам:
Ресурс1 = 0, то в качестве текста ячейки выведем специальный маркер, например, строку <УдалитьСтроку>.ПриКомпоновкеРезультата.Ниже представлен пример программного кода для реализации этого подхода:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
// Стандартный вывод отчета в Табличный Документ
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.ПолучитьНастройки(), ДанныеРасшифровки);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки, Истина);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
// Поиск и удаление помеченных строк
ТекущаяОбласть = ДокументРезультат.НайтиТекст("<УдалитьСтроку>");
Пока ТекущаяОбласть <> Неопределено Цикл
// Удаляем строку целиком по вертикали
НомерСтроки = ТекущаяОбласть.Верх;
ДокументРезультат.УдалитьОбласть(ДокументРезультат.Область(НомерСтроки, 1, НомерСтроки, ДокументРезультат.ШиринаТаблицы), ТипСмещенияТабличногоДокумента.ПоВертикали);
// Ищем следующий маркер
ТекущаяОбласть = ДокументРезультат.НайтиТекст("<УдалитьСтроку>");
КонецЦикла;
КонецПроцедуры
Преимущество метода: гарантируется 100% точное удаление ненужных визуальных строк без какого-либо влияния на математику расчета итогов в СКД. Общие итоги будут посчитаны абсолютно корректно.
---
Если мы не хотим писать программный код удаления строк, но нам нужно визуально скрыть строки с нулевыми итогами, можно воспользоваться «хитростью» условного оформления:
Ресурс1 Равно 0.0.1 (или минимально возможному значению платформы), а также сделаем цвет текста и цвет границ совпадающими с цветом фона.Строки визуально «схлопнутся» и станут незаметными для глаза. Однако помните, что при копировании данных в Excel или при печати эти строки все равно могут отображаться в виде очень тонких полос, поэтому данный способ рекомендуется использовать только как крайнюю альтернативу.