Почему возникает ошибка в СКД при заполнении только одного параметра и как правильно настроить необязательные отборы?

Программист 1С v8.3 (Обычные формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

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

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

Разбор типичной ошибки в синтаксисе запроса

Рассмотрим ситуацию, с которой столкнулся автор темы. В запросе к виртуальной таблице остатков и оборотов было прописано следующее условие:


ВЫБРАТЬ
    ОстаткиПоСериямОстаткиИОбороты.Серия,
    ОстаткиПоСериямОстаткиИОбороты.Номенклатура,
    ОстаткиПоСериямОстаткиИОбороты.Склад
ИЗ
    РегистрНакопления.ОстаткиПоСериям.ОстаткиИОбороты(
        {(&НачалоПериода)}, 
        {(&КонецПериода)}, 
        Авто, , 
        {(Склад = &Склад ИЛИ Номенклатура = &Номенклатура)}
    ) КАК ОстаткиПоСериямОстаткиИОбороты

Проанализируем причину ошибки. Когда мы заключаем условие в фигурные скобки {}, мы говорим системе компоновки: «этот блок кода должен быть включен в итоговый запрос только в том случае, если соответствующие параметры заполнены пользователем». Однако, объединяя два параметра через ИЛИ внутри одних фигурных скобок, мы создаем единый неделимый блок.

Если пользователь заполняет только «Номенклатуру», СКД видит, что один из параметров внутри блока активирован, и пытается подставить в итоговый SQL-запрос всю конструкцию: (Склад = &Склад ИЛИ Номенклатура = &Номенклатура). Но так как параметр &Склад не был инициализирован (не выбран пользователем), система не может корректно сформировать запрос к базе данных, что и приводит к ошибке выполнения.

Решение №1: Разделение условий на независимые блоки

Самый простой и правильный способ сделать параметры необязательными в СКД — это вынести каждое условие в отдельные фигурные скобки. В этом случае система будет обрабатывать их независимо друг от друга. Если заполнен только один параметр, в запрос попадет только одно условие.

Изменим запрос в параметрах виртуальной таблицы следующим образом:


ГДЕ 
    {(Склад = &Склад)} 
    И {(Номенклатура = &Номенклатура)}

Важный нюанс: при таком подходе условия будут соединяться по логическому «И». Если пользователю требуется именно логика «ИЛИ» (показать движения либо по конкретному складу, либо по конкретному товару), этот метод не подойдет в чистом виде, так как СКД не умеет динамически менять И на ИЛИ между разными блоками расширения запроса.

Решение №2: Использование конструкции ВЫБОР в запросе

Если нам критически важно сохранить проверку параметров именно через ИЛИ и при этом избежать ошибок при пустых значениях, можно воспользоваться проверкой на пустую ссылку. Выясним, как это реализовать прямо в тексте запроса.

Мы можем написать условие, которое будет проверять, заполнено ли значение параметра. Если параметр пуст, условие всегда будет возвращать ИСТИНА, тем самым не влияя на результат выборки.


{ (ВЫБОР 
    КОГДА &Склад <> ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка) 
        ТОГДА Склад = &Склад 
    ИНАЧЕ ИСТИНА 
 КОНЕЦ 
 ИЛИ 
 ВЫБОР 
    КОГДА &Номенклатура <> ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка) 
        ТОГДА Номенклатура = &Номенклатура 
    ИНАЧЕ ИСТИНА 
 КОНЕЦ) }

Рассмотрим подробнее, как это работает. Даже если блок в фигурных скобках активируется, конструкция ВЫБОР корректно обрабатывает пустые значения параметров, подставляя ИСТИНА вместо фильтрации. Однако помните, что использование сложных логических конструкций в параметрах виртуальных таблиц может негативно сказаться на производительности (плане выполнения запроса в СУБД).

Решение №3: Отказ от параметров запроса в пользу отборов СКД

Для программиста на 1С наиболее «чистым» и рекомендуемым способом является использование стандартного механизма отборов компоновки данных. Вместо того чтобы вручную прописывать параметры в тексте запроса, мы можем положиться на механизм Автозаполнение.

  1. Удалим все упоминания &Склад и &Номенклатура из текста запроса и из параметров виртуальной таблицы.
  2. На вкладке «Настройки» в схеме компоновки данных перейдем в раздел «Отбор».
  3. Добавим поля «Склад» и «Номенклатура» в список доступных отборов.
  4. Установим для них свойство «Включать в пользовательские настройки».

При таком подходе СКД сама проанализирует запрос. Если в запросе используется виртуальная таблица, система автоматически применит выбранные пользователем фильтры максимально эффективно — передаст их в параметры виртуальной таблицы базы данных. Это исключает риск возникновения синтаксических ошибок при незаполнении полей.

Почему важна типизация параметров?

Проанализируем еще один технический момент, упомянутый в обсуждении. В СКД существует разница между пустой ссылкой конкретного типа и значением Неопределено.

Если в настройках схемы на вкладке «Параметры» у параметра не задан тип или не указано начальное значение, то при открытии отчета там может находиться Неопределено. Сравнение СправочникСсылка = Неопределено в запросе может вести себя непредсказуемо или вызывать ошибку. Поэтому:

Итоги

Подводя итог, для создания надежного отчета в 1С 8.3 рекомендуется:

  1. Избегать объединения разных параметров через ИЛИ внутри одной пары фигурных скобок {}.
  2. Использовать стандартные отборы компоновки вместо жестко заданных параметров в запросе везде, где это возможно.
  3. Если логика «ИЛИ» обязательна, использовать конструкцию ВЫБОР КОГДА с проверкой на пустую ссылку, предварительно задав типы параметров в схеме.

Соблюдение этих правил позволит создавать гибкие отчеты, которые не «падают» при попытке пользователя выполнить фильтрацию по неполным данным.

← На главную