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

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

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

Вариант 1. Выборка элементов со всей глубиной вложенности через оператор В ИЕРАРХИИ

Если нам необходимо получить элементы, которые лежат как непосредственно в указанных группах, так и в любых созданных внутри них подпапках, применяется оператор В ИЕРАРХИИ. В качестве параметра данному оператору можно передавать не только одну ссылку, но и массив, список значений или результат подзапроса.

Важно помнить: условие Ссылка В ИЕРАРХИИ (&СписокГрупп) вернет не только подчиненные элементы, но и сами группы, переданные в списке. Чтобы в выборку попали исключительно элементы, добавим условие отсечения групп.

Посмотрим на пример запроса для справочника с типом иерархии «Иерархия групп и элементов»:


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

Запрос.УстановитьПараметр("СписокГрупп", СписокВыбранныхГрупп);
РезультатЗапроса = Запрос.Выполнить();

Разберем по шагам важные особенности этого механизма:

  1. Реквизит ЭтоГруппа доступен только для справочников с иерархией групп и элементов. Если у справочника настроена «Иерархия элементов», такого реквизита в таблице базы данных нет. В этом случае для исключения исходных узлов-родителей следует использовать условие: И НЕ Номенклатура.Ссылка В (&СписокГрупп).
  2. Передача параметров: если в параметр &СписокГрупп передан пустой массив или пустой список значений, запрос вернет пустую выборку. Если же передать Неопределено, платформа выдаст ошибку выполнения запроса.
  3. Пустая ссылка: если среди элементов списка передать пустую ссылку справочника, платформа посчитает корнем всё дерево и в результат попадут все записи таблицы.

Вариант 2. Выборка только прямых потомков без погружения вглубь

Если задача состоит в том, чтобы выбрать элементы, находящиеся строго на первом уровне указанных групп (без вложенных подгрупп), использовать оператор В ИЕРАРХИИ избыточно. Для этого достаточно наложить прямое условие на реквизит Родитель с помощью оператора В.

Рассмотрим пример такого запроса:


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

Запрос.УстановитьПараметр("СписокГрупп", СписокВыбранныхГрупп);
РезультатЗапроса = Запрос.Выполнить();

Такой подход работает быстрее, поскольку поле Родитель в платформе 1С стандартно проиндексировано СУБД, и системе не требуется выполнять рекурсивный обход дерева.

Оптимизация производительности при большом списке групп

На уровне СУБД оператор В ИЕРАРХИИ транслируется в рекурсивные CTE-запросы или многократные соединения. Если переданный массив групп содержит десятки или сотни значений, производительность запроса может существенно деградировать.

Для ускорения работы рекомендуется поместить массив групп во временную таблицу и использовать ее в качестве источника для иерархического отбора:


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

Запрос.УстановитьПараметр("МассивГрупп", МассивГруппНоменклатуры);
РезультатЗапроса = Запрос.Выполнить();

Использование отборов в СКД и динамических списках

Если мы настраиваем отбор программно в Системе компоновки данных (СКД) или в Динамическом списке на форме, важно правильно указывать тип сравнения:

  1. Для единичной группы используется вид сравнения ВидСравненияКомпоновкиДанных.ВИерархии (или ВидСравнения.ВИерархии).
  2. Для списка или массива групп необходимо указывать ВидСравненияКомпоновкиДанных.ВИерархииСписка (или ВидСравнения.ВИерархииСписка).
← На главную