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

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

При разработке отчетов или обработок в 1С часто возникает классическая задача: необходимо отфильтровать данные по нескольким полям (например, Контрагент и Торговый представитель), при этом параметры могут быть как заполнены оба, так и по отдельности, или не заполнены вовсе. Если просто прописать их в блоке ГДЕ через И, то при незаполненном одном поле запрос ничего не вернет. Если через ИЛИ — логика может нарушиться.

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

Способ 1. Динамическое формирование текста запроса

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


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

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

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

Плюсы этого метода: СУБД получает максимально лаконичный SQL-текст, что помогает ей эффективно строить план выполнения запроса и использовать индексы.

Минусы: Код становится громоздким. Если параметров станет не 2, а 5, количество комбинаций Если...ИначеЕсли вырастет в геометрической прогрессии, и поддерживать такой код будет невозможно.

Способ 2. Использование универсальных условий (Boolean Flags)

Это более профессиональный и элегантный подход. Мы оставляем текст запроса статичным, но добавляем в него специальные параметры-флаги, которые «включают» или «выключают» нужные фильтры. Разберем, как это реализовать.

В тексте запроса напишем следующее условие в блоке ГДЕ:


ГДЕ (&ОтборПоКонтрагенту = ЛОЖЬ ИЛИ Таблица.Контрагент = &Контрагент)
  И (&ОтборПоТП = ЛОЖЬ ИЛИ Таблица.Агент = &ТорговыйПредставитель)

Теперь проанализируем программную часть. Перед выполнением запроса нам нужно правильно установить параметры:


Запрос.УстановитьПараметр("Контрагент", Контрагент);
Запрос.УстановитьПараметр("ОтборПоКонтрагенту", ЗначениеЗаполнено(Контрагент));

Запрос.УстановитьПараметр("ТорговыйПредставитель", ТорговыйПредставитель);
Запрос.УстановитьПараметр("ОтборПоТП", ЗначениеЗаполнено(ТорговыйПредставитель));

Как это работает: Если параметр Контрагент не заполнен, мы передаем в &ОтборПоКонтрагенту значение ЛОЖЬ. В результате первая часть условия (&ОтборПоКонтрагенту = ЛОЖЬ ИЛИ ...) всегда становится истинной (ИСТИНА ИЛИ что-угодно), и фильтр по контрагенту просто игнорируется системой.

Способ 3. Конструкция ВЫБОР в запросе

Еще один вариант — использование логики выбора прямо внутри SQL-запроса. Это позволяет обрабатывать пустые значения без склейки строк. Рассмотрим пример реализации:


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

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

Важные нюансы и оптимизация производительности

Проанализируем технические моменты, которые могут повлиять на корректность результата и скорость работы программы:

  1. Работа с типами данных: В 1С пустое значение справочника — это не NULL и не Неопределено. Это специфический объект «Пустая ссылка». Поэтому при проверке в коде используем ЗначениеЗаполнено(), а в запросе сравниваем с ЗНАЧЕНИЕ(Справочник.ИмяСправочника.ПустаяСсылка).
  2. Производительность индексов: При использовании условий с ИЛИ (как в Способе 2 и 3) СУБД иногда может отказаться от использования индексов и перейти к полному сканированию таблицы (Table Scan). На огромных таблицах в сотни тысяч строк первый способ (динамическая склейка) может работать быстрее.
  3. Использование ЕСТЬNULL: Если вы делаете левое соединение (например, получаете данные торгового представителя из другой таблицы), поле может содержать NULL. В таких случаях обязательно оборачивайте поля в функцию: ЕСТЬNULL(Таблица.Агент, ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка)).
  4. Система компоновки данных (СКД): Если ваша задача — вывести результат в отчет или табличную часть, лучшим решением будет использование СКД. Вам достаточно добавить нужные поля в список отборов на закладке «Настройки», и 1С сама сформирует максимально оптимальный запрос в зависимости от того, какие галочки поставил пользователь. Это избавляет от написания сложной логики вручную.

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

← На главную