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

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

В процессе разработки отчетов в системе 1С:Предприятие 8 часто возникает классическая задача: предоставить пользователю возможность отбора по списку значений (например, по конкретным сотрудникам, номенклатуре или организациям). При этом логика должна работать следующим образом: если пользователь выбрал конкретные элементы, отчет формируется только по ним; если же отбор оставлен пустым, система должна проигнорировать это условие и вывести абсолютно все записи.

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

Выясним причины некорректного поведения исходного запроса и разберем по шагам правильные методики реализации такой логики.

---

Анализ исходной проблемы и логической ошибки в запросе

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


ГДЕ
    &КоличествоСотрудников = 0
            ИЛИ ВТ_Итоговая0.Сотрудник В (&СотрудникиОтчета)
    И НЕ ВТ_Итоговая0.Сотрудник.ПометкаУдаления
                И (ВТ_Итоговая0.Организация = &Организация
                    ИЛИ &Организация = ЗНАЧЕНИЕ(Справочник.Организации.ПустаяСсылка))
                И (ВТ_Итоговая0.ДатаУвольнения = ДАТАВРЕМЯ(1, 1, 1)
                        И НЕ &УчитыватьУволенных
                    ИЛИ &УчитыватьУволенных
                        И ВТ_Итоговая0.ДатаУвольнения >= ДАТАВРЕМЯ(2014, 1, 1))

В этой конструкции скрываются сразу две серьезные ошибки, из-за которых запрос работает не так, как ожидается:

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

Рассмотрим подробнее несколько способов решения этой задачи.

---

Решение 1. Исправление ручной проверки количества (Быстрый способ)

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

Проанализируем исправленную секцию ГДЕ в тексте запроса:


ГДЕ
    // Обязательно берем проверку списка в отдельные скобки!
    (&КоличествоСотрудников = 0 
        ИЛИ ВТ_Итоговая0.Сотрудник В (&СотрудникиОтчета))
    
    // Все остальные условия накладываются независимо от того, пустой список или нет
    И НЕ ВТ_Итоговая0.Сотрудник.ПометкаУдаления
    И (ВТ_Итоговая0.Организация = &Организация
        ИЛИ &Организация = ЗНАЧЕНИЕ(Справочник.Организации.ПустаяСсылка))
    И (ВТ_Итоговая0.ДатаУвольнения = ДАТАВРЕМЯ(1, 1, 1)
            И НЕ &УчитыватьУволенных
        ИЛИ &УчитыватьУволенных
            И ВТ_Итоговая0.ДатаУвольнения >= ДАТАВРЕМЯ(2014, 1, 1))

Теперь в модуле объекта или формы, где происходит вызов отчета и устанавливаются параметры, необходимо передать количество элементов списка в параметр &КоличествоСотрудников:


// Установка параметров в компоновщике настроек СКД
ПараметрыДанных = Отчет.КомпоновщикНастроек.Настройки.ПараметрыДанных;

ПараметрыДанных.УстановитьЗначениеПараметра("Организация", Организация);
ПараметрыДанных.УстановитьЗначениеПараметра("СотрудникиОтчета", СотрудникиОтчета);
ПараметрыДанных.УстановитьЗначениеПараметра("УчитыватьУволенных", УчитыватьУволенных);
ПараметрыДанных.УстановитьЗначениеПараметра("КонецПериода", ТекущаяДата());

// Обязательно передаем количество элементов списка!
ПараметрыДанных.УстановитьЗначениеПараметра("КоличествоСотрудников", СотрудникиОтчета.Количество());

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

---

Решение 2. Использование необязательных условий СКД (Рекомендуемый способ)

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

Давайте разберем по шагам, как переписать условие профессионально. Мы можем полностью убрать параметр количества сотрудников и обернуть условие фильтрации в фигурные скобки. В этом случае СКД сама проанализирует: если параметр &СотрудникиОтчета заполнен пользователем, условие будет добавлено в итоговый SQL-запрос. Если же список пуст или галочка использования параметра снята, СКД просто вырежет это условие из текста запроса перед его отправкой на СУБД.

Посмотрим на пример реализации в тексте запроса СКД:


ГДЕ
    НЕ ВТ_Итоговая0.Сотрудник.ПометкаУдаления
    И (ВТ_Итоговая0.Организация = &Организация
        ИЛИ &Организация = ЗНАЧЕНИЕ(Справочник.Организации.ПустаяСсылка))
    И (ВТ_Итоговая0.ДатаУвольнения = ДАТАВРЕМЯ(1, 1, 1)
            И НЕ &УчитыватьУволенных
        ИЛИ &УчитыватьУволенных
            И ВТ_Итоговая0.ДатаУвольнения >= ДАТАВРЕМЯ(2014, 1, 1))
            
    // Необязательное условие компоновки данных:
    {ГДЕ ВТ_Итоговая0.Сотрудник В (&СотрудникиОтчета)}

Преимущества этого подхода очевидны:

---

Решение 3. Проверка на пустоту списка внутри «чистого» запроса (без СКД)

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

Если мы не хотим передавать второй параметр количества, мы можем проверить список на пустоту прямо внутри запроса, сделав подзапрос к любой реальной таблице базы данных (например, к справочнику сотрудников). Рассмотрим этот изящный прием:


ГДЕ
    (ВТ_Итоговая0.Сотрудник В (&СотрудникиОтчета)
        ИЛИ НЕ 1 В 
            (ВЫБРАТЬ ПЕРВЫЕ 1 1 
             ИЗ Справочник.Сотрудники КАК Спр 
             ГДЕ Спр.Ссылка В (&СотрудникиОтчета)))

Как работает эта логика:

---

Решение 4. Динамическое формирование текста запроса в коде

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

Рассмотрим пример реализации:


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

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

// Заменяем маркер на сформированное условие
Запрос.Текст = СтрЗаменить(ТекстЗапроса, "//_УсловиеПоСотрудникам", СтрокаУсловия);

Этот метод гарантирует максимальную производительность, так как в СУБД уходит максимально оптимизированный SQL-текст без лишней логики ветвления.

---

Важная проблема: Скрытая пустая строка в списке параметров СКД

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

В чем причина?

Когда в пользовательских настройках СКД добавлен отбор или параметр со списком значений, платформа 1С при инициализации формы отчета может автоматически добавить в этот СписокЗначений одну пустую строку (со значением Неопределено или пустой ссылкой на справочник сотрудников). Пользователь видит на экране пустую таблицу отбора, но физически в объекте списка присутствует один элемент.

В итоге:

Как решить эту проблему?

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


// Очистка списка от пустых элементов (обход с конца коллекции)
Индекс = СотрудникиОтчета.Количество() - 1;
Пока Индекс >= 0 Цикл
    ТекущееЗначение = СотрудникиОтчета[Индекс].Значение;
    Если Не ЗначениеЗаполнено(ТекущееЗначение) Тогда
        СотрудникиОтчета.Удалить(Индекс);
    КонецЕсли;
    Индекс = Индекс - 1;
КонецЦикла;

// Теперь количество будет определено абсолютно корректно!
ПараметрыДанных.УстановитьЗначениеПараметра("КоличествоСотрудников", СотрудникиОтчета.Количество());
ПараметрыДанных.УстановитьЗначениеПараметра("СотрудникиОтчета", СотрудникиОтчета);

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

← На главную