Как обойти ошибку Не задано значение параметра при проверке списка в запросе СКД

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

Выясним причину ошибки: особенности валидации параметров в 1С

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


ГДЕ
    &ИспользоватьСписокДолжностей = ЛОЖЬ
    ИЛИ br_РезультатыЗвонка.Звонящий.Должность В (&СписокДолжностей)

Кажется интуитивным, что если параметр &ИспользоватьСписокДолжностей равен значению Ложь, то платформа не должна обращать внимания на вторую часть выражения. Однако в платформе 1С действует строгий механизм предварительной проверки параметров:

  1. Предварительная валидация параметров. Перед тем как отправить запрос в СУБД, платформа проверяет, установлены ли значения абсолютно для всех параметров, объявленных через символ & в основном тексте запроса. В 1С отсутствует концепция «ленивых вычислений» при подготовке текста запроса к выполнению: ни логический оператор ИЛИ, ни конструкция ВЫБОР КОГДА ... ТОГДА не отменяют необходимость передать значение в каждый упомянутый параметр.
  2. Поведение оператора В со пустым списком. Даже если разработчик передаст в параметр пустой массив или пустой список значений, СУБД преобразует такое выражение в заведомо ложное условие (эквивалент 1 = 0). В результате запрос выполнится без ошибок, но отфильтрует все строки, вместо того чтобы показать все данные без отбора.

Способ 1. Использование расширения языка запросов СКД (фигурные скобки)

В системе компоновки данных существует специальный синтаксис — расширение языка запросов. Фрагменты условий, заключенные в фигурные скобки {ГДЕ ...}, обрабатываются компоновщиком макета динамически: если параметр или поле не задействованы в настройках отчета, компоновщик полностью вырезает этот блок из итогового текста SQL-запроса.

Проанализируем пример кода с использованием расширения:


{ГДЕ
    (br_РезультатыЗвонка.Звонящий.Должность В (&СписокДолжностей))
}

Рассмотрим порядок действий для настройки этого варианта:

  1. Удалим из основного текста запроса секцию ГДЕ с логическим оператором ИЛИ и управляющим флагом &ИспользоватьСписокДолжностей — отдельный флаг больше не требуется.
  2. Поместим условие фильтрации в фигурные скобки.
  3. Перейдем на вкладку Параметры схемы компоновки данных. Найдем параметр СписокДолжностей и убедимся, что для него снят флажок Запрещать незаполненные значения (или настроена возможность отключения параметра пользователем).

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

Способ 2. Отказ от жестких условий в пользу стандартных отборов СКД

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

Разберем по шагам, как реализовать этот подход:

  1. Очистим секцию ГДЕ в тексте запроса от условий по полю должности. Запрос должен просто выбирать необходимые данные:
    
    ВЫБРАТЬ
        br_РезультатыЗвонка.Ссылка КАК Ссылка,
        br_РезультатыЗвонка.Звонящий.Должность КАК Должность
    ИЗ
        Документ.br_РезультатыЗвонка КАК br_РезультатыЗвонка
    
  2. Перейдем на вкладку Настройки схемы компоновки данных в раздел Отбор.
  3. Добавим новый элемент отбора: в левом поле выберем Звонящий.Должность, вид сравнения укажем В списке, а правое значение оставим пустым.
  4. Включим отображение этого отбора в пользовательских настройках (в нижней панели настроек установим признак Включать в пользовательские настройки).

При таком подходе пользователь сам решает, активировать ли отбор флажком. Если отбор отключен, СКД не включает никаких лишних условий в результирующий SQL-запрос, что обеспечивает максимальную производительность и исключает ошибки валидации параметров.

Способ 3. Описание доступных полей отбора через расширение запроса

Если необходимо явно объявить поле для отбора в расширении запроса (например, для переименования или явного указания доступности), применим следующий синтаксис:


ВЫБРАТЬ
    br_РезультатыЗвонка.Ссылка КАК Ссылка
ИЗ
    Документ.br_РезультатыЗвонка КАК br_РезультатыЗвонка
{ГДЕ
    br_РезультатыЗвонка.Звонящий.Должность.* КАК Должность}

Символ .* указывает компоновщику, что данное поле доступно для любых видов сравнения в пользовательских настройках (Равно, В списке, В иерархии и т. д.). Фильтрация применится только тогда, когда пользователь непосредственно задаст значение отбора.

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

Если запрос формируется в обычном программном модуле через объект Запрос, фигурные скобки СКД не сработают. В таком случае динамическое поведение реализуется через проверку заполненности в коде 1С:


Запрос = Новый Запрос;
ТекстЗапроса = 
    "ВЫБРАТЬ
    |   br_РезультатыЗвонка.Ссылка КАК Ссылка
    |ИЗ
    |   Документ.br_РезультатыЗвонка КАК br_РезультатыЗвонка";

Если ЗначениеЗаполнено(СписокДолжностей) Тогда
    ТекстЗапроса = ТекстЗапроса + "
    |ГДЕ
    |   br_РезультатыЗвонка.Звонящий.Должность В (&СписокДолжностей)";
    Запрос.УстановитьПараметр("СписокДолжностей", СписокДолжностей);
КонецЕсли;

Запрос.Текст = ТекстЗапроса;
Результат = Запрос.Выполнить();

Таким образом, мы исключаем появление неинициализированных параметров в тексте запроса и гарантируем корректное выполнение выборки данных как в СКД, так и в классическом коде встроенного языка 1С.

← На главную