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