Как задать условие для необязательного параметра в запросе 1С?

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

Часто при разработке отчетов или обработок на платформе 1С возникает необходимость гибко фильтровать данные. Проанализируем ситуацию: у нас есть форма с полем выбора контрагента. Если пользователь выбрал контрагента, запрос должен отфильтровать документы только по нему. Если же поле осталось пустым, необходимо вывести все документы без ограничений. Разберем по шагам, как правильно реализовать такое условие в тексте запроса, избежав при этом проблем с производительностью.

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

Рассмотрим первый метод, который часто приходит на ум при решении подобной задачи. Мы можем использовать встроенную конструкцию условия внутри секции ГДЕ.

Посмотрим на пример кода:


ВЫБОР 
    КОГДА &Контрагент = ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка) 
    ТОГДА ИСТИНА 
    ИНАЧЕ ТаблицаИсточник.Контрагент = &Контрагент 
КОНЕЦ

Этот подход проверяет параметр на пустую ссылку. Если параметр пуст, условие возвращает ИСТИНА, и фильтрация отключается. В противном случае происходит сравнение поля с переданным значением.

Вариант 2: Логическое ИЛИ

Многие разработчики предпочитают более компактную запись с использованием логического оператора ИЛИ. Выясним причину такой популярности — код становится визуально короче.


ГДЕ (&Контрагент = РеализацияТоваровУслуг.Контрагент ИЛИ &Контрагент = ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка))

Также возможен вариант с оператором В:


ГДЕ &Контрагент В (РеализацияТоваровУслуг.Контрагент, ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка))

Проблема производительности: почему эти варианты могут быть опасны?

Несмотря на то, что приведенные выше примеры рабочие, использовать их в высоконагруженных системах или на больших объемах данных категорически не рекомендуется. Рассмотрим подробнее, что происходит на уровне СУБД (например, MS SQL или PostgreSQL).

Когда оптимизатор базы данных видит в секции ГДЕ сложные логические развилки (особенно конструкции ИЛИ или ВЫБОР КОГДА), он часто не может использовать индексы таблицы. Вместо быстрого поиска по индексу (Index Seek), система начинает полное сканирование всей таблицы (Table Scan). Это может привести к тому, что запрос, который должен выполняться доли секунды, будет работать несколько минут и «повесит» базу.

Вариант 3: Динамическое формирование текста запроса (Лучшая практика для встроенного языка)

Если мы пишем запрос программно с использованием встроенного языка 1С, наиболее грамотным решением будет изменять саму строку запроса до его выполнения. Разберем этот подход.

Мы формируем базовый текст запроса без спорного условия, а затем добавляем его только в том случае, если параметр действительно заполнен пользователем.


ТекстЗапроса = "
    |ВЫБРАТЬ
    |    РеализацияТоваровУслуг.Ссылка
    |ИЗ
    |    Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
    |ГДЕ
    |    НЕ РеализацияТоваровУслуг.ПометкаУдаления
    |    И РеализацияТоваровУслуг.Дата МЕЖДУ &ДатаНачала И &ДатаКонец";

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

Запрос.Текст = ТекстЗапроса;

В этом случае на сервер базы данных отправляется максимально простой и оптимизированный SQL-код, который легко отрабатывает по индексам.

Вариант 4: Расширения языка запросов для СКД

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


ВЫБРАТЬ
    РеализацияТоваровУслуг.Ссылка
ИЗ
    Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
ГДЕ
    НЕ РеализацияТоваровУслуг.ПометкаУдаления
    И РеализацияТоваровУслуг.Дата МЕЖДУ &ДатаНачала И &ДатаКонец
{ГДЕ 
    РеализацияТоваровУслуг.Контрагент = &Контрагент}

Как это работает? Если пользователь в настройках СКД не заполнил параметр Контрагент или отключил соответствующий отбор, платформа автоматически «вырежет» блок внутри фигурных скобок еще до трансляции запроса в СУБД. Никаких проблем с производительностью не возникнет.

Важные нюансы работы с пустыми значениями

При написании условий обращайте внимание на типы данных. Рассмотрим частые ошибки:

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

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

← На главную