Как правильно настроить условия фильтрации в СКД при работе с параметрами и виртуальными таблицами?

Программист 1С v8.3 (Управляемые формы) 1С:ERP Управление предприятием Управленческий учет Промышленность, строительство и АПК
← На главную

В процессе разработки отчетов на базе Системы компоновки данных (СКД) программисты часто сталкиваются с необходимостью реализовать гибкую фильтрацию, которая зависит от выбора пользователя. Типичный пример — вывод только «незакрытых» заказов на производство. На первый взгляд, задача кажется простой, но использование сложных логических конструкций внутри запроса может привести к непредсказуемым результатам, ошибкам исполнения и существенному замедлению работы отчета.

В этой статье мы подробно проанализируем, почему стандартные подходы с использованием оператора ВЫБОР в секции ГДЕ могут не работать, и рассмотрим наиболее эффективные способы реализации условий в СКД.

Анализ проблемы: почему CASE (ВЫБОР) в секции ГДЕ — это плохая идея

Рассмотрим ситуацию, когда разработчик пытается внедрить сложную логику проверки параметра прямо в текст запроса. Часто это выглядит следующим образом:


ГДЕ
    ВЫБОР
        КОГДА &ТолькоНезакрытые
            ТОГДА Регистратор В (ВЫБРАТЬ Заказ ИЗ ВТ_Остатки)
        ИНАЧЕ ИСТИНА
    КОНЕЦ

Проанализируем, что здесь не так. Во-первых, оператор ВЫБОР в языке запросов 1С должен возвращать конкретное значение (например, число, строку или булево), а не само логическое условие. Попытка вставить конструкцию Поле В (Подзапрос) внутрь ТОГДА синтаксически некорректна для секции ГДЕ в классическом SQL и может вызывать ошибки компиляции запроса в 1С.

Во-вторых, использование ВЫБОР в условиях лишает оптимизатор СУБД возможности использовать индексы. СУБД не может заранее построить эффективный план выполнения, так как условие становится «динамическим» на уровне каждой строки таблицы. Это приводит к полному сканированию данных (Table Scan), что на больших регистрах (таких как «Заказы на производство») критично для производительности.

Разбор механизма необязательных условий в фигурных скобках {}

Система компоновки данных предоставляет механизм фигурных скобок для описания условий, которые должны включаться в запрос только при наличии заполненного параметра или установленного отбора. Рассмотрим пример:

{ГДЕ (Регистратор.*)}

Многие начинающие разработчики полагают, что если обернуть сложный ВЫБОР в фигурные скобки, СКД «сама разберется». Однако важно понимать правила:

  1. Если параметр внутри {} не заполнен, СКД просто вырезает весь блок из итогового текста запроса.
  2. Если вы используете параметр &ТолькоНезакрытые внутри скобок, но при этом он помечен в схеме как «Автозаполнение» или «Обязательный», система выдаст ошибку Не задано значение параметра, если пользователь не установит флажок в настройках.
  3. Если логика внутри скобок слишком запутана (как в случае с вложенными подзапросами), СКД может некорректно интерпретировать метаданные полей, что приведет к попаданию в отчет лишних данных, которые вы проверяли в консоли запросов.

Решение №1: Использование классической булевой логики

Самый надежный и быстрый способ реализовать включение отбора по параметру — это использование связки НЕ &Параметр ИЛИ (Условие). Проанализируем, как это выглядит на практике для задачи с незакрытыми заказами:


ГДЕ
    (НЕ &ТолькоНезакрытые)
    ИЛИ (ЗаказыНаПроизводствоОстаткиИОбороты.Регистратор В 
            (ВЫБРАТЬ Остатки.ЗаказНаПроизводство ИЗ ОстаткиПоЗаказам КАК Остатки))

Как это работает? Разберем по шагам:

  1. Если пользователь снял галочку ТолькоНезакрытые (значение ЛОЖЬ), то первая часть НЕ ЛОЖЬ превращается в ИСТИНА. Согласно законам логики, всё выражение ИСТИНА ИЛИ (...) всегда равно ИСТИНА. Вторая часть с подзапросом даже не будет влиять на результат.
  2. Если пользователь установил галочку (значение ИСТИНА), то НЕ ИСТИНА превращается в ЛОЖЬ. Условие принимает вид ЛОЖЬ ИЛИ (Условие). В этом случае итоговый результат строки зависит исключительно от выполнения условия во второй части скобок.

Этот метод позволяет избежать использования ВЫБОР и корректно обрабатывает ситуацию, когда параметр всегда присутствует в запросе, но его влияние нужно включать или выключать.

Решение №2: Оптимизация через параметры виртуальных таблиц

Рассмотрим ситуацию глубже. В примере автора используется виртуальная таблица ОстаткиИОбороты. Накладывать фильтр в секции ГДЕ на данные виртуальной таблицы — это значит сначала заставить систему получить все итоги из базы, а потом отсеивать их. Гораздо эффективнее передать условие в параметры самой виртуальной таблицы.

Выясним причину, почему в отчет попадают лишние строки. При использовании периодичности «Авто» поле Регистратор для записей остатков на начало периода может содержать NULL. Чтобы избежать этого и повысить скорость, выполним следующие действия:

  1. Создадим временную таблицу ВТ_ОткрытыеЗаказы, где соберем только те заказы, по которым есть остаток.
  2. В параметрах виртуальной таблицы ЗаказыНаПроизводство.ОстаткиИОбороты укажем условие фильтрации по этой временной таблице.

// Сначала выбираем открытые заказы
ВЫБРАТЬ
    ЗаказыНаПроизводствоОстатки.ЗаказНаПроизводство КАК Заказ
ПОМЕСТИТЬ ВТ_ОткрытыеЗаказы
ИЗ
    РегистрНакопления.ЗаказыНаПроизводство.Остатки КАК ЗаказыНаПроизводствоОстатки;

// Затем используем их в основном запросе
ВЫБРАТЬ
    ...
ИЗ
    РегистрНакопления.ЗаказыНаПроизводство.ОстаткиИОбороты(,, Авто,, 
        ЗаказНаПроизводство В (ВЫБРАТЬ Заказ ИЗ ВТ_ОткрытыеЗаказы)
    ) КАК Заказы

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

РегистрНакопления.ЗаказыНаПроизводство.ОстаткиИОбороты(,, Авто,, {ЗаказНаПроизводство.*})

Решение №3: Обработка типа Регистратора

В тексте обсуждения упоминается проверка ТИПЗНАЧЕНИЯ(Регистратор) = ТИП(Документ.ЗаказНаПроизводство). Рассмотрим подробнее, как сделать это оптимальнее. Вместо функции ТИПЗНАЧЕНИЯ, которая работает медленнее, используем оператор ССЫЛКА. Проанализируем итоговое условие, которое объединяет все требования:


ГДЕ
    (НЕ &ТолькоЗаказыНаПроизводство ИЛИ Заказы.Регистратор ССЫЛКА Документ.ЗаказНаПроизводство)
    И
    (НЕ &ТолькоНеЗакрытые ИЛИ Заказы.Регистратор В (ВЫБРАТЬ Заказ ИЗ ВТ_ОткрытыеЗаказы))

Такой подход гарантирует:

Помните, что в СКД поле Регистратор часто ведет себя специфично. Если вы видите в отчете пустые строки, которые «не отсекаются», проверьте Роли полей на закладке «Набор данных». Возможно, СКД добавляет эти строки для расчета итогов по периодам или группировкам, даже если они не удовлетворяют условию ГДЕ. В таком случае поможет установка флага «Обязательное» для условий или использование ВНУТРЕННЕЕ СОЕДИНЕНИЕ вместо условий в ГДЕ.

← На главную