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