Как в запросе 1С выбрать всю номенклатуру или фильтровать по выбранной группе

Программист IT и автоматизация бизнеса
← На главную

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

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

Причина проблемы: типизация и логика условия «В ИЕРАРХИИ»

Рассмотрим ситуацию, с которой столкнулся автор темы. В коде использовалась тернарная операция для установки параметра:

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

Проанализируем этот фрагмент. Здесь в случае, если переменная Группа пуста, в запрос передается пустая строка "". Однако в самом тексте запроса этот параметр сравнивается со ссылочным типом данных справочника Номенклатура. В системе 1С:Предприятие пустая строка и пустая ссылка — это абсолютно разные типы. Попытка использовать строку в условии В ИЕРАРХИИ приведет либо к ошибке выполнения, либо к неявному приведению типов, которое не даст ожидаемого результата (выбора всех элементов).

Способ №1: Использование пустой ссылки (самый простой вариант)

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


Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|	Номенклатура.Ссылка КАК Номенклатура
|ИЗ
|	Справочник.Номенклатура КАК Номенклатура
|ГДЕ
|	Номенклатура.Ссылка В ИЕРАРХИИ(&Группа)
|	И НЕ Номенклатура.ЭтоГруппа";

// Вместо пустой строки передаем пустую ссылку справочника
ПустаяГруппа = Справочники.Номенклатура.ПустаяСсылка();
Запрос.УстановитьПараметр("Группа", ?(ЗначениеЗаполнено(Группа), Группа, ПустаяГруппа));

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

Как это работает: Платформа 1С обрабатывает условие В ИЕРАРХИИ специфическим образом. Если в качестве параметра передана пустая ссылка, система считает, что «родителем» является корень справочника. Так как все элементы справочника находятся в корне, условие В ИЕРАРХИИ с пустой ссылкой вернет все записи. Это решение является рабочим, но у него есть минус — производительность. Оператор В ИЕРАРХИИ на уровне SQL-запроса преобразуется в достаточно сложную конструкцию (часто с использованием временных таблиц), и выполнять ее для всей таблицы не всегда оптимально.

Способ №2: Универсальное условие в тексте запроса

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


Запрос.Текст = 
"ВЫБРАТЬ
|	Номенклатура.Ссылка КАК Номенклатура
|ИЗ
|	Справочник.Номенклатура КАК Номенклатура
|ГДЕ
|	(&Группа = ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка) 
|		ИЛИ Номенклатура.Ссылка В ИЕРАРХИИ(&Группа))
|	И НЕ Номенклатура.ЭтоГруппа";

Проанализируем это условие. Если параметр &Группа является пустой ссылкой, первая часть условия (до ИЛИ) становится истинной для всех строк таблицы. Вторая часть (проверка иерархии) в этом случае может даже не вычисляться оптимизатором СУБД. Если же группа заполнена, будет работать проверка вхождения в иерархию.

Важный нюанс: Такая конструкция может негативно сказаться на производительности («SARGability»). Оптимизатору СУБД сложнее построить оптимальный план выполнения (Index Seek) при наличии условий с ИЛИ, объединяющих константы и поля таблиц. На больших объемах данных это может привести к полному сканированию таблицы (Table Scan).

Способ №3: Динамическое формирование текста запроса

С точки зрения производительности СУБД, самым правильным подходом является исключение лишних условий из текста запроса еще до его выполнения. Разберем, как это сделать программно:


ТекстУсловия = "";
Если ЗначениеЗаполнено(Группа) Тогда
    ТекстУсловия = "ГДЕ Номенклатура.Ссылка В ИЕРАРХИИ(&Группа) И НЕ Номенклатура.ЭтоГруппа";
Иначе
    ТекстУсловия = "ГДЕ НЕ Номенклатура.ЭтоГруппа";
КонецЕсли;

Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ Номенклатура.Ссылка КАК Номенклатура ИЗ Справочник.Номенклатура КАК Номенклатура " + ТекстУсловия;

Если ЗначениеЗаполнено(Группа) Тогда
    Запрос.УстановитьПараметр("Группа", Группа);
КонецЕсли;

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

Способ №4: Использование Системы компоновки данных (СКД)

Если вы разрабатываете отчет, лучше всего использовать встроенные механизмы СКД. В СКД задача решается установкой «Фигурных скобок» в тексте запроса:


ВЫБРАТЬ
	Номенклатура.Ссылка КАК Номенклатура
ИЗ
	Справочник.Номенклатура КАК Номенклатура
{ГДЕ
	(Номенклатура.Ссылка В ИЕРАРХИИ (&Группа))}

В чем преимущество: Если пользователь не выберет значение параметра &Группа в настройках отчета, платформа 1С самостоятельно вырежет блок ГДЕ из итогового SQL-запроса. Это обеспечивает максимальную гибкость и производительность без написания дополнительного кода на встроенном языке.

Итоги и рекомендации

Подведем итоги нашего анализа и выделим основные правила работы с необязательными фильтрами по иерархии:

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

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

← На главную