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

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

В практике разработки на платформе 1С:Предприятие часто возникает задача создания универсального отчета или обработки, где пользователю предоставляется несколько полей для фильтрации данных. Основная сложность заключается в реализации логики «необязательных параметров»: если пользователь заполнил фильтр, программа должна отобрать данные по этому значению, а если оставил поле пустым — вывести все записи без исключения по данному критерию.

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

Способ 1. Использование конструкции ВЫБОР в секции ГДЕ

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

Проанализируем пример кода, реализующий этот алгоритм:


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

Как работает эта логика? Когда платформа 1С выполняет запрос, она вычисляет условие для каждой строки. Если в параметр &Работа передана пустая ссылка, блок ВЫБОР сразу возвращает ИСТИНА, и фильтрация по конкретному значению работы не производится. Если же параметр заполнен, выполняется сравнение поля таблицы с переданным значением.

Важный нюанс: при проверке на пустое значение необходимо учитывать тип данных. Для ссылочных типов (Справочники, Документы) мы используем ЗНАЧЕНИЕ(...ПустаяСсылка), а для простых типов или составных полей может потребоваться проверка на НЕОПРЕДЕЛЕНО или NULL.

Способ 2. Элегантная проверка через оператор В

Существует более лаконичный способ записи того же самого условия. Мы можем использовать оператор В, передав в него массив из двух элементов: само значение поля и признак «пустоты». Однако в контексте параметров запроса это выглядит еще проще — мы проверяем, входит ли наш параметр в список, состоящий из значения поля в базе и «пустого» значения.

Посмотрим на пример сокращенной записи:


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

Выясним причину популярности этого метода. Он значительно сокращает объем текста запроса, делая его более читаемым. Если параметр &Работа пустой, то условие превращается в ПустаяСсылка В (ПустаяСсылка, Поле), что всегда ИСТИНА. Если параметр заполнен конкретной ссылкой, условие выполняется только тогда, когда эта ссылка совпадает с ИсторияРасценок.Работа.

Способ 3. Динамическое формирование текста запроса (Best Practice)

Хотя предыдущие методы удобны, у них есть существенный недостаток — производительность. Использование ВЫБОР или сложных условий с ИЛИ (которые СУБД видит за оператором В) часто мешает оптимизатору SQL использовать индексы таблиц. Это может привести к полному сканированию таблицы (Full Scan), что критично для больших регистров.

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


ТекстУсловия = "";
МассивУсловий = Новый Массив;

Если ЗначениеЗаполнено(Работа) Тогда
    МассивУсловий.Добавить("ИсторияРасценок.Работа = &Работа");
КонецЕсли;

Если ЗначениеЗаполнено(Груз) Тогда
    МассивУсловий.Добавить("ИсторияРасценок.Груз = &Груз");
КонецЕсли;

Если МассивУсловий.Количество() > 0 Тогда
    ТекстУсловия = "ГДЕ " + СтрСоединить(МассивУсловий, " И ");
КонецЕсли;

ТекстЗапроса = 
    "ВЫБРАТЬ
    |   ИсторияРасценок.Цена
    |ИЗ
    |   РегистрСведений.ИсторияРасценок КАК ИсторияРасценок
    |" + ТекстУсловия;

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

Способ 4. Система компоновки данных (СКД)

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

Разберем основные преимущества использования СКД для фильтрации:

  1. Автоматическая оптимизация: СКД сама анализирует, какие параметры заполнены, и включает в SQL-запрос только нужные условия.
  2. Гибкость для пользователя: Вы можете вынести отборы на форму, и платформа сама обработает пустые значения без написания кода.
  3. Использование фигурных скобок: В запросе СКД можно использовать конструкцию {ГДЕ Поле = &Параметр}. Если параметр не заполнен, условие внутри скобок будет проигнорировано платформой автоматически.

Даже если вам не нужно выводить отчет, вы можете программно инициализировать схему компоновки, установить настройки отбора и выгрузить результат в ТаблицуЗначений. Это обеспечит максимальную производительность и чистоту кода.

Проблема NULL и пустых значений

Проанализируем важный технический аспект: разницу между пустой ссылкой и отсутствием значения. В 1С поле может содержать:

Если в вашем регистре поле может принимать значение NULL, обычное сравнение ИсторияРасценок.Объект = &Объект вернет ЛОЖЬ, даже если &Объект тоже NULL (в 1С NULL не равен NULL). В таких случаях рекомендуется использовать функцию ЕСТЬNULL в тексте запроса, чтобы привести значения к единому типу перед сравнением.

Рекомендации по выбору метода

Подведем итог и определим, какой метод использовать в зависимости от ситуации:

  1. Для небольших таблиц и простых обработок идеально подходят методы из способов 1 и 2. Они просты в написании и не требуют сложной логики формирования строки.
  2. Для высоконагруженных систем и больших объемов данных (миллионы записей) используйте динамическое формирование текста запроса. Это гарантирует использование индексов СУБД.
  3. Для отчетов всегда выбирайте СКД. Это стандарт платформы, который берет на себя всю работу по управлению необязательными фильтрами.

Используя эти приемы, мы создаем гибкие и надежные механизмы поиска и фильтрации данных, которые корректно ведут себя при любом наборе заполненных параметров.

← На главную