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