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