При разработке отчетов на базе Системы компоновки данных (СКД) программисты часто сталкиваются с необходимостью наложить гибкие условия на периоды. Типичная задача: если пользователь задал дату, отчет должен фильтроваться по ней, а если оставил поле пустым — выводить все данные. Однако попытка реализовать это через стандартные конструкции ВЫБОР КОГДА часто приводит к ошибкам исполнения запроса. Разберем детально, почему это происходит и как правильно проектировать такие условия.
Рассмотрим ситуацию, описанную в теме. Автор пытается использовать конструкцию вида:
И (ВЫБОР
КОГДА &НачалоПериода <> ДАТАВРЕМЯ(1, 1, 1)
ТОГДА &НачалоПериода <= КП.Дата
ИНАЧЕ ИСТИНА
КОНЕЦ)
На первый взгляд логика верна: мы проверяем, не является ли дата пустой (01.01.0001). Но при исполнении система выдает ошибку. Проанализируем причину. В СКД каждый параметр имеет флаг «Использование». Если пользователь в настройках отчета (на вкладке «Параметры» или в пользовательских настройках) снимает галочку с параметра &НачалоПериода, то для СКД этого параметра больше не существует в контексте выполнения текущего запроса.
Когда генератор запросов встречает прямое обращение к &НачалоПериода (вне специальных операторов), он пытается подставить туда значение. Если параметр «выключен», подставлять нечего, и выполнение прерывается с ошибкой. Таким образом, нужно различать два состояния: параметр не используется (выключен флаг) и параметр пуст (флаг стоит, но значение — пустая дата).
Самый простой способ избежать ошибки «в лоб» — убедиться, что параметр всегда доступен запросу. Разберем по шагам, как это настроить в конструкторе СКД:
НачалоПериода.Однако такой подход заставляет нас писать громоздкие условия ВЫБОР в самом тексте запроса, что снижает читаемость и может негативно сказаться на производительности (плане запроса СУБД). Рассмотрим более профессиональные методы.
Система компоновки данных обладает мощным механизмом — расширением языка запросов. Это специальные инструкции в фигурных скобках {}, которые подсказывают СКД, как модифицировать запрос в зависимости от настроек пользователя. Рассмотрим ситуацию, когда нам нужно наложить условие на дату только в том случае, если пользователь активировал этот параметр.
Вместо сложной логики ВЫБОР в секции ГДЕ или в условии соединения ПО, мы напишем следующее:
ГДЕ
{КП.Дата >= &НачалоПериода, КП.Дата <= &ОкончаниеПериода}
Как это работает? Проанализируем поведение системы:
ГДЕ КП.Дата >= ? И КП.Дата <= ?.&НачалоПериода, но оставил &ОкончаниеПериода, СКД автоматически вырежет часть условия, и в итоговом SQL-запросе останется только ГДЕ КП.Дата <= ?.ГДЕ будет полностью удалена из запроса, и мы получим все записи без фильтрации по датам.Это самый эффективный и «чистый» способ работы в СКД.
Иногда нам принципиально нужно, чтобы параметр всегда участвовал в запросе, но мы хотим переопределить «пустую дату» на какое-то экстремальное значение (например, начало времен или конец времен), чтобы условие сравнения работало корректно. Выясним, как это сделать без изменения текста запроса.
На закладке Параметры в СКД есть колонка Выражение. Мы можем прописать там логику на языке выражений СКД:
Для параметра &НачалоПериода:
ВЫБОР КОГДА &НачалоПериода = ДАТАВРЕМЯ(1,1,1) ТОГДА ДАТАВРЕМЯ(1900,1,1) ИНАЧЕ &НачалоПериода КОНЕЦ
Для параметра &ОкончаниеПериода:
ВЫБОР КОГДА &ОкончаниеПериода = ДАТАВРЕМЯ(1,1,1) ТОГДА ДАТАВРЕМЯ(3999,12,31) ИНАЧЕ КонецПериода(&ОкончаниеПериода, "День") КОНЕЦ
В этом случае в тексте запроса можно будет использовать простейшее сравнение КП.Дата МЕЖДУ &НачалоПериода И &ОкончаниеПериода, и оно всегда будет отрабатывать логически верно, даже если пользователь не заполнил даты.
Для удобства пользователя и разработчика рекомендуется использовать один параметр типа СтандартныйПериод вместо двух отдельных дат. Рассмотрим, как это упрощает жизнь:
ПериодОтчета с типом СтандартныйПериод.&НачалоПериода и &ОкончаниеПериода (которые используются в тексте запроса) в колонке «Выражение» укажем:
&ПериодОтчета.ДатаНачала&ПериодОтчета.ДатаОкончанияТеперь пользователь выбирает период через удобный интерфейс (например, «Этот месяц»), а СКД сама корректно заполняет даты. Если период не выбран, даты будут пустыми, и здесь снова вступят в силу правила из Решения 2 или Решения 3.
Если условие на дату стоит в секции ПО при левом соединении таблиц, нужно быть особенно осторожным. Проанализируем ситуацию: если мы напишем ЛЕВОЕ СОЕДИНЕНИЕ ... ПО Т1.Ссылка = Т2.Ссылка И Т2.Дата >= &НачалоПериода, и параметр будет отключен, СКД может повести себя по-разному в зависимости от версии платформы.
Правильным подходом для соединений будет использование расширения компоновки данных непосредственно внутри секции ПО:
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Контрагенты КАК КП
ПО ОсновнаяТаблица.Контрагент = КП.Ссылка
{И КП.Дата >= &НачалоПериода}
Важный момент: если вы используете ВЫБОР КОГДА внутри условий запроса, помните замечание из сообщения №2 форума: логические операции вроде A > B не возвращают тип Булево, который можно было бы просто «вернуть» из ВЫБОР. В языке запросов 1С они могут находиться только в условиях ГДЕ, ПО или ИМЕЮЩИЕ. Внутри ВЫБОР вы обязаны явно возвращать значения: ТОГДА ИСТИНА ИНАЧЕ ЛОЖЬ.
Подводя итог, можно сказать, что лучшая практика для СКД — это максимальный отказ от ручного управления параметрами через ВЫБОР КОГДА в тексте запроса в пользу использования фигурных скобок и настройки выражений параметров. Это делает отчет надежным, а код запроса — понятным и оптимизированным.