Как использовать поле запроса или вычисляемое значение в выражении параметра СКД?

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

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

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

Ограничения языка выражений СКД

Часто возникает желание получить нужные даты прямо в основном запросе СКД, а затем использовать эти поля в выражении для параметра, например, так:


ВЫБОР КОГДА &ПЕРИОД = "СезонПродаж" ТОГДА ДатаНачалаСезонаПродаж ИНАЧЕ ДатаНачалаНеСезонаПродаж КОНЕЦ

СКД может не выдать синтаксическую ошибку при сохранении схемы, но при формировании отчета возникнет "Ошибка в выражении". Дело в том, что вычисление параметров в СКД происходит до того, как формируется и выполняется основной запрос к базе данных. На момент вычисления параметра полей из запроса еще просто не существует.

Вторая распространенная ошибка — попытка написать SQL-подобный запрос непосредственно внутри выражения параметра СКД:


ВЫБОР КОГДА &ПЕРИОДОТЧЕТА = "СезонПродаж" ТОГДА (ВЫБРАТЬ НастройкиСистемы.Значение ИЗ Справочник.НастройкиСистемы КАК НастройкиСистемы ГДЕ НастройкиСистемы.Ссылка = &НачалоСезонаПродаж) ИНАЧЕ &ДатаНачалаНеСезонаПродаж КОНЕЦ

Важно понимать: язык выражений СКД выполняется на уровне сервера приложений 1С отдельно от СУБД. В нем строго запрещено использование конструкций языка запросов (ВЫБРАТЬ ... ИЗ ...). Поэтому такой подход не сработает.

Разберем рабочие и архитектурно правильные способы решения этой задачи.

Способ 1. Использование функций общих модулей в выражениях СКД

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

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

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

Способ 2. Программная инициализация параметров (рекомендуемый подход)

Наиболее гибким и "чистым" архитектурным подходом считается отказ от сложных вызовов в самих выражениях СКД в пользу подготовки данных до начала генерации отчета. Выясним, как это сделать через модуль объекта отчета.

Воспользуемся стандартным обработчиком события ПриКомпоновкеРезультата. Внутри этого обработчика мы можем выполнить обычный 1С-запрос к базе данных, получить точные даты сезона или несезона и программно установить их прямо в параметры компоновщика настроек.


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

Этот подход позволяет полностью избежать проблем с кэшированием выражений СКД и делает код более прозрачным для отладки.

Способ 3. Использование типа "СтандартныйПериод"

Вместо того чтобы оперировать двумя отдельными параметрами (начало и окончание), в СКД принято использовать единый параметр с типом СтандартныйПериод.

Если мы программно определим даты сезона (как в Способе 2), мы можем создать объект СтандартныйПериод, назначить ему эти даты и передать в настройки СКД. В самом тексте запроса СКД к границам этого периода можно будет обращаться очень лаконично и удобно: &Период.ДатаНачала и &Период.ДатаОкончания. Это сократит количество параметров и сделает схему более стандартной.

Способ 4. Динамическая подмена текста запроса СКД

Посмотрим на более сложный сценарий. Что если сезонные и несезонные продажи требуют не только разных дат, но и применения разных условий или даже обращения к разным таблицам? В таком случае 1С позволяет динамически менять сам текст запроса.

В том же событии ПриКомпоновкеРезультата мы можем проанализировать выбранный пользователем параметр и программно переписать свойство Запрос у набора данных схемы компоновки до того, как процессор СКД начнет получать данные. Это дает абсолютную свободу в формировании логики отчета.

← На главную