Как в запросе 1С исключить родительскую группу, но оставить элементы вложенной в неё подгруппы

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

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

Метод 1: Использование логического оператора «ИЛИ» в условии «ГДЕ»

Самый простой и интуитивно понятный способ — это объединение двух условий в блоке ГДЕ. Рассмотрим ситуацию на примере. У нас есть иерархия: Аксессуары (родитель), внутри которой находятся Тип 1 и Тип 2. Нам нужно исключить всё, что в «Аксессуарах», кроме «Типа 2».

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


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

Важный нюанс: Обратите внимание на логику работы этого условия. Если элемент находится в «Типе 2», он автоматически находится и в «Аксессуарах». Условие НЕ Товары.Ссылка В ИЕРАРХИИ (&ПапкаАксессуары) вернет для него Ложь, но вторая часть условия через ИЛИ (вхождение в «Тип 2») вернет Истина. В результате элемент будет включен в выборку. Для всех остальных элементов из «Аксессуаров» (например, из «Типа 1») оба условия вернут Ложь, и они будут отсечены.

Метод 2: Объединение запросов (ОБЪЕДИНИТЬ)

Если логика фильтрации становится слишком громоздкой или вы опасаетесь, что СУБД некорректно построит план запроса при сложном ИЛИ, можно использовать конструкцию ОБЪЕДИНИТЬ. Этот метод часто оказывается более «прозрачным» для оптимизатора SQL.

Разберем, как это работает по шагам:

  1. В первом запросе мы выбираем все данные, полностью исключая родительскую иерархию &ПапкаАксессуары.
  2. Во втором запросе мы принудительно выбираем только те элементы, которые входят в иерархию разрешенной подпапки &ПапкаТип2.
  3. Используем ОБЪЕДИНИТЬ (не ОБЪЕДИНИТЬ ВСЕ, чтобы исключить дубли, если они теоретически возможны, хотя в данном случае условия исключают друг друга).

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

ОБЪЕДИНИТЬ

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

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

Метод 3: Оптимизация через временные таблицы

Профессиональная разработка в 1С подразумевает заботу о производительности. Оператор В ИЕРАРХИИ является ресурсоемким, так как платформа на уровне SQL выполняет рекурсивные запросы или использует дополнительные таблицы индексов иерархии. Если иерархия справочника очень глубокая, а данных много, лучше заранее подготовить список разрешенных групп.

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

  1. Создадим временную таблицу, в которую поместим все ссылки на группы, входящие в разрешенную подпапку.
  2. В основном запросе заменим тяжелое условие В ИЕРАРХИИ на простое сравнение В (ВЫБРАТЬ... ИЗ ВременнаяТаблица) или на левое соединение.

// 1. Получаем все вложенные папки для разрешенной иерархии
ВЫБРАТЬ
    Номенклатура.Ссылка КАК Группа
ПОМЕСТИТЬ ВТ_РазрешенныеГруппы
ИЗ
    Справочник.Номенклатура КАК Номенклатура
ГДЕ
    Номенклатура.Ссылка В ИЕРАРХИИ(&ПапкаТип2)
    И Номенклатура.ЭтоГруппа = ИСТИНА
;

// 2. Основная выборка
ВЫБРАТЬ
    Товары.Ссылка
ИЗ
    Справочник.Номенклатура КАК Товары
ГДЕ
    (НЕ Товары.Родитель В ИЕРАРХИИ(&ПапкаАксессуары)
    ИЛИ Товары.Родитель В (ВЫБРАТЬ Группа ИЗ ВТ_РазрешенныеГруппы))

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

Анализ производительности и влияние индексов

Выясним причину, по которой запросы с условием НЕ В ИЕРАРХИИ могут работать медленно. В базах данных SQL Server или PostgreSQL использование отрицания (NOT) часто приводит к тому, что оптимизатор отказывается от использования индексов (происходит Index Scan вместо Index Seek). Это означает, что системе приходится просматривать всю таблицу целиком.

Рекомендации по ускорению:

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

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

  1. Добавьте новую Группу условий ИЛИ.
  2. Внутри этой группы добавьте первое условие: Номенклатура НЕ В Иерархии "Аксессуары".
  3. Вторым условием в этой же группе добавьте: Номенклатура В Иерархии "Аксессуары типа 2".

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

Заключение

Мы проанализировали ситуацию, когда необходимо реализовать «выборочную» иерархию в запросе. Самым быстрым в написании является использование логики (НЕ ... ИЛИ ...), однако для высоконагруженных систем рекомендуется использовать метод объединения запросов или предварительную подготовку списка групп во временных таблицах. Выбор метода зависит от объема данных в вашем справочнике и требований к скорости выполнения операции.

← На главную