Почему в СКД не работает условие в запросе и виртуальная таблица СрезПоследних возвращает пустой результат

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

Анализ проблемы: иллюзия неработающего параметра

Представим типовую конструкцию запроса, в которой логика ветвления зависит от пользовательского булевого параметра &ПоказатьОрганизацию и левого соединения с регистром сведений:


ВЫБРАТЬ
    НастройкиОрганизации.Организация КАК Организация
ПОМЕСТИТЬ НастройкиОрганизаций
ИЗ
    РегистрСведений.НастройкиОрганизации.СрезПоследних КАК НастройкиОрганизации
ГДЕ
    НастройкиОрганизации.СкрыватьОрганизации;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ОстаткиДоговоров.Наименование,
    ВЫБОР
        КОГДА &ПоказатьОрганизацию
            ТОГДА ОстаткиДоговоров.Организация
        ИНАЧЕ ВЫБОР
                КОГДА НастройкиОрганизаций.Организация ЕСТЬ NULL 
                    ТОГДА ОстаткиДоговоров.Организация
                ИНАЧЕ NULL
            КОНЕЦ
    КОНЕЦ КАК Организация
ИЗ
    ОстаткиДоговоров КАК ОстаткиДоговоров
    ЛЕВОЕ СОЕДИНЕНИЕ НастройкиОрганизаций КАК НастройкиОрганизаций
    ПО ОстаткиДоговоров.Организация = НастройкиОрганизаций.Организация

На форме отчета флаг &ПоказатьОрганизацию выключен (значение Ложь), однако отчет все равно выводит все организации, как если бы параметр был равен Истина. При проверке этого же запроса в обычной консоли запросов всё работает корректно. Выясним, почему так происходит.

Причина 1: Скрытое поведение виртуальной таблицы СрезПоследних в СКД

В обычной консоли запросов, если у виртуальной таблицы РегистрСведений.НастройкиОрганизации.СрезПоследних() не указан параметр Период, платформа не накладывает ограничение по дате и берет срез на текущий момент времени.

В СКД при включенном свойстве Автозаполнение поведение принципиально иное:

  1. Механизм компоновки автоматически добавляет параметры для всех виртуальных таблиц.
  2. Если параметр периода виртуальной таблицы не был явно инициализирован или передан, СКД подставляет в него пустую дату: 01.01.0001 00:00:00.
  3. В результате срез на начало нашей эры возвращает абсолютно пустую таблицу НастройкиОрганизаций.
  4. При левом соединении поле НастройкиОрганизаций.Организация всегда принимает значение NULL.
  5. В выражении ВЫБОР срабатывает ветка КОГДА НастройкиОрганизаций.Организация ЕСТЬ NULL ТОГДА ОстаткиДоговоров.Организация, что приводит к выводу организации независимо от значения параметра &ПоказатьОрганизацию.

Способы решения проблемы с виртуальной таблицей

Способ 1. Использование расширения языка запросов компоновки данных (фигурные скобки)

Чтобы параметр периода виртуальной таблицы не применялся при его отсутствии (и срез брался на актуальное время), обращение к параметру периода необходимо обернуть в синтаксис расширения языка СКД:


ИЗ
    РегистрСведений.НастройкиОрганизации.СрезПоследних({(&Период)}, ) КАК НастройкиОрганизации

Если параметр &Период не передан или отключен, компоновщик данных не будет передавать пустую дату в срез.

Способ 2. Автоматическое вычисление текущей даты на вкладке «Параметры»

Если для среза требуется всегда использовать текущий момент или начало дня, настраиваем параметр в схеме компоновки данных без программного кода:

  1. Переходим на вкладку Параметры в схеме СКД.
  2. Находим параметр периода виртуальной таблицы (или создаем собственный, например, &ТекущаяДата).
  3. В колонке Выражение указываем стандартную функцию: ТекущаяДатаСеанса() или НачалоПериода(ТекущаяДатаСеанса(), "ДЕНЬ").
  4. Устанавливаем флаг Ограничение доступности, чтобы скрыть служебный параметр от пользователя.

Особенности работы с типом «СтандартныйПериод» и выражениями параметров

Если в отчете используется пользовательский параметр с типом СтандартныйПериод (например, &ПериодОтчета), мы можем рассчитывать зависимые даты прямо в выражениях СКД:

  1. Дата начала периода: &ПериодОтчета.ДатаНачала
  2. Дата окончания периода: &ПериодОтчета.ДатаОкончания
  3. Конец дня для корректного включения последней секунды: КонецПериода(&ПериодОтчета.ДатаОкончания, "ДЕНЬ")

Важный нюанс отладки выражений: метод КомпоновщикНастроек.ПолучитьНастройки() возвращает структуру настроек до того, как формулы из колонки «Выражение» будут вычислены. В точке останова отладчика значение параметра может отображаться как 01.01.0001. Реальный расчет выражений происходит на этапе формирования макета объектом КомпоновщикМакета.

Программная установка параметров и взаимодействие с формой

Если настройки отчета выводятся на пользовательскую управляемую форму, изменение параметров в коде требует внимательности. Если параметр входит в состав пользовательских настроек, его значение в КомпоновщикНастроек.Настройки будет перекрыто коллекцией КомпоновщикНастроек.ПользовательскиеНастройки.

Для надежной программной установки параметров компоновщика настроек используем следующий подход:


// Установка значения в основных настройках
ПараметрПериод = КомпоновщикНастроек.Настройки.ПараметрыДанных.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("Период"));
Если ПараметрПериод <> Неопределено Тогда
    ПараметрПериод.Значение = ТекущаяДатаСеанса();
    ПараметрПериод.Использование = Истина;
КонецЕсли;

// Установка значения в пользовательских настройках (если параметр выведен пользователю)
Для Каждого Элемент Из КомпоновщикНастроек.ПользовательскиеНастройки.Элементы Цикл
    Если ТипЗнч(Элемент) = Тип("ЗначениеПараметраНастроекКомпоновкиДанных") 
        И Элемент.Параметр = Новый ПараметрКомпоновкиДанных("Период") Тогда
        Элемент.Значение = ТекущаяДатаСеанса();
        Элемент.Использование = Истина;
    КонецЕсли;
КонецЦикла;

Как увидеть реальный SQL-запрос, сформированный СКД

Чтобы убедиться, какие именно значения параметров и условий попали в итоговый запрос, проанализируем сгенерированный макет компоновки в модуле отчета:


КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(
    СхемаКомпоновкиДанных, 
    КомпоновщикНастроек.ПолучитьНастройки(), 
    ДанныеРасшифровки
);

// Получаем итоговый текст запроса со всеми подстановками
Для Каждого НаборДанных Из МакетКомпоновки.НаборыДанных Цикл
    Если ТипЗнч(НаборДанных) = Тип("МакетКомпоновкиНабораДанныхЗапрос") Тогда
        ТекстРеальногоЗапроса = НаборДанных.Запрос;
        // ТекстРеальногоЗапроса можно просмотреть в отладчике или вывести в журнал
    КонецЕсли;
КонецЦикла;

Такой подход позволяет моментально увидеть различия между текстом запроса в схеме и фактически исполняемым запросом СУБД со всеми срезами и условиями.

← На главную