При разработке отчетов на базе системы компоновки данных (СКД) разработчики часто сталкиваются с ситуацией: без условий по датам отчет выводит строки корректно, но стоит добавить отбор по периоду — результат становится абсолютно пустым, даже если в информационной базе точно есть записи за указанный интервал. Проанализируем причины такого поведения и пошагово разберем методы решения проблемы и оптимизации схемы компоновки данных.
Выясним основные причины, из-за которых отбор по датам отсекает все записи:
НачалоПериода и КонецПериода имеют состав даты «Только дата», время автоматически приводится к 00:00:00. В этом случае жесткое условие Период <= &КонецПериода исключает все движения, совершенные в течение конечного дня интервала, кроме документов, записанных строго в полночь.{}), СКД обязана передать их значения в СУБД. Если в пользовательских настройках флажок использования параметра снят или значение не выбрано, платформа подставляет пустую дату (0001-01-01 00:00:00). В результате условие не выполняется ни для одной строки.РегистрНакопления.Продажи напрямую только ради получения документа-регистратора, полагая, что в виртуальных таблицах оборотов этого поля нет. При прямом чтении СУБД сканирует всю таблицу, а не оптимизированные итоги, что ухудшает производительность и повышает риск блокировок.Разберем, как правильно получить документ движения без обращения к физической таблице. Виртуальная таблица РегистрНакопления.Продажи.Обороты содержит поле Регистратор, если в параметрах таблицы указать соответствующую периодичность.
Посмотрим на пример правильного запроса для СКД:
ВЫБРАТЬ
ПродажиОбороты.Номенклатура КАК Номенклатура,
ПродажиОбороты.Склад КАК Склад,
ПродажиОбороты.Контрагент КАК Контрагент,
ПродажиОбороты.ЦенаОборот КАК Цена,
ПродажиОбороты.КоличествоОборот КАК Количество,
ПродажиОбороты.Регистратор КАК Регистратор,
ПродажиОбороты.ЦенаОборот * ПродажиОбороты.КоличествоОборот КАК Сумма
ИЗ
РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, Регистратор, ) КАК ПродажиОбороты
Обратим внимание на третий параметр виртуальной таблицы: значение Регистратор указывает платформе разворачивать обороты с детализацией до документа движения. Это позволяет получить точные данные без обращения к таблице движений регистра напрямую.
Чтобы избежать отсечения документов из-за времени 00:00:00 и исключить пустые даты, свяжем границы с параметром типа СтандартныйПериод. Разберем настройку по шагам:
ПериодОтчета, и назначим ему тип СтандартныйПериод. Сделаем его доступным для пользователя в настройках.НачалоПериода и КонецПериода установим флажок Ограничение доступности, чтобы скрыть их из диалога настроек.НачалоПериода укажем:
&ПериодОтчета.ДатаНачалаКонецПериода пропишем формулу:
КонецПериода(&ПериодОтчета.ДатаОкончания, "День")Данная конструкция гарантирует, что конец периода всегда будет указывать на последнюю секунду дня (23:59:59), а параметры всегда будут заполнены согласованно.
Если накладывать условия отбора через секцию ГДЕ после выборки данных, СУБД сначала сформирует полный оборот по всем записям, а затем отфильтрует результат. Правильный подход — передавать условия отбора непосредственно в четвертый параметр виртуальной таблицы, используя расширение языка запросов СКД в фигурных скобках {}.
Рассмотрим пример запроса с оптимальной фильтрацией:
ВЫБРАТЬ
ПродажиОбороты.Номенклатура КАК Номенклатура,
ПродажиОбороты.Склад КАК Склад,
ПродажиОбороты.Контрагент КАК Контрагент,
ПродажиОбороты.ЦенаОборот КАК Цена,
ПродажиОбороты.КоличествоОборот КАК Количество,
ПродажиОбороты.Регистратор КАК Регистратор,
ПродажиОбороты.ЦенаОборот * ПродажиОбороты.КоличествоОборот КАК Сумма
ИЗ
РегистрНакопления.Продажи.Обороты(
&НачалоПериода,
&КонецПериода,
Регистратор,
{(Склад = &Склад), (Номенклатура.Родитель В ИЕРАРХИИ (&Категория))}
) КАК ПродажиОбороты
Фигурные скобки внутри параметров виртуальной таблицы указывают СКД, что отбор является необязательным. Если пользователь не заполнил поле Склад или Категория, СКД не будет включать это условие в итоговый запрос к СУБД. Если же отбор задан, фильтрация произойдет на самом раннем этапе выборки данных.
Когда отчет возвращает пустой результат, полезно проанализировать фактический текст запроса, который компоновщик формирует перед отправкой в СУБД. Для этого используем программный перехват через объект КомпоновщикМакетаКомпоновкиДанных:
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.ПолучитьНастройки());
// Выводим фактический текст запроса первого набора данных
ТекстФактическогоЗапроса = МакетКомпоновки.НаборыДанных[0].Запрос;
// Проверяем реальные значения переданных параметров
Для Каждого Параметр Из МакетКомпоновки.ЗначенияПараметров Цикл
Сообщить(Параметр.Имя + " = " + Строка(Параметр.Значение));
КонецЦикла;
Проанализировав полученный текст и параметры, можно сразу увидеть, какое условие исключает строки и какое значение передается в границы дат.