В практике разработки на платформе 1С:Предприятие часто возникает задача ограничения выборки данных на основе настроек конкретного пользователя. Типичный пример: у объекта Пользователь есть реквизит ПапкаНоменклатуры, и нам необходимо в запросе получить все элементы, которые входят в эту группу, включая все вложенные подпапки. Сложность заключается в том, что в запрос передается только ссылка на пользователя, а иерархический поиск должен отработать корректно для любой глубины вложенности.
Рассмотрим детально, как решить эту задачу максимально эффективно, разберем типичные ошибки и проанализируем поведение системы при различных подходах.
Многие начинающие разработчики полагают, что оператор В ИЕРАРХИИ может принимать только внешние параметры, переданные из встроенного языка. Однако, начиная с версии платформы 8.2, система официально поддерживает использование подзапросов внутри этого оператора. Это позволяет решить задачу буквально в одно предложение.
Проанализируем текст запроса, который позволяет извлечь данные, имея в качестве параметра только ссылку на пользователя:
ВЫБРАТЬ
Номенклатура.Ссылка КАК Ссылка
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
Номенклатура.Ссылка В ИЕРАРХИИ (
ВЫБРАТЬ
Пользователи.ПапкаНоменклатуры
ИЗ
Справочник.Пользователи КАК Пользователи
ГДЕ
Пользователи.Ссылка = &Пользователь
)
В данном примере система сначала выполнит вложенный запрос к справочнику Пользователи, получит ссылку на группу номенклатуры, а затем использует её как корень для построения иерархического списка. Важно отметить, что если в реквизите ПапкаНоменклатуры будет пустое значение или NULL, запрос вернет пустой результат, что является ожидаемым поведением.
Несмотря на изящность первого варианта, с точки зрения производительности СУБД (особенно на больших объемах данных) использование временных таблиц часто оказывается предпочтительным. Рассмотрим, почему это так. Когда мы используем подзапрос непосредственно в условии ГДЕ, планировщик запросов СУБД не всегда может оптимально построить план выполнения, особенно если иерархия справочника Номенклатура имеет большую глубину.
Разберем по шагам создание запроса с использованием временной таблицы:
// Шаг 1: Получаем целевую папку во временную таблицу
ВЫБРАТЬ
Пользователи.ПапкаНоменклатуры КАК ЦелеваяПапка
ПОМЕСТИТЬ ВТ_ПапкаПользователя
ИЗ
Справочник.Пользователи КАК Пользователи
ГДЕ
Пользователи.Ссылка = &Пользователь
;
////////////////////////////////////////////////////////////////////////////////
// Шаг 2: Выбираем иерархию номенклатуры
ВЫБРАТЬ
Номенклатура.Ссылка КАК Ссылка
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
Номенклатура.Ссылка В ИЕРАРХИИ (
ВЫБРАТЬ
ВТ_ПапкаПользователя.ЦелеваяПапка
ИЗ
ВТ_ПапкаПользователя КАК ВТ_ПапкаПользователя
)
Такой подход позволяет платформе 1С более явно сформировать инструкции для SQL-сервера. Это особенно актуально, если запрос является частью сложного отчета или динамического списка.
Иногда предлагается использовать ЛЕВОЕ СОЕДИНЕНИЕ по условию Номенклатура.Родитель = Пользователь.ПапкаНоменклатуры. Давайте выясним причину, по которой этот метод не является решением поставленной задачи.
Проблема заключается в том, что условие по равенству родителя выбирает только первый уровень вложенности. Если внутри целевой папки "Продукты" есть подпапка "Молочные продукты", а в ней — "Кефир", то при обычном соединении по родителю "Кефир" в выборку не попадет. Оператор В ИЕРАРХИИ — это единственный способ в языке запросов 1С автоматически обойти все уровни дерева без написания рекурсивных алгоритмов на встроенном языке.
При использовании иерархических запросов важно помнить о следующих технических аспектах:
Родитель в стандартных справочниках 1С всегда индексировано. Это позволяет механизму В ИЕРАРХИИ работать достаточно быстро, так как поиск дочерних элементов происходит по индексу.ПапкаНоменклатуры попадет обычный элемент (не группа), запрос отработает корректно, но вернет только этот один элемент. Это штатное поведение системы.&Пользователь.ПапкаНоменклатуры напрямую в операторе В ИЕРАРХИИ невозможно. Параметр должен быть либо простой ссылкой, либо результатом подзапроса. Обращение через точку в тексте запроса (например, ГДЕ Номенклатура.Ссылка В ИЕРАРХИИ (Пользователь.ПапкаНоменклатуры)) заставит систему неявно добавлять соединение, что может негативно сказаться на читаемости и производительности.В ходе обсуждения подобных задач часто возникает вопрос: насколько рационально хранить ограничение доступа или фильтрацию через одну папку? Если одному пользователю нужно видеть номенклатуру из разных папок, жесткая привязка к одному реквизиту типа СправочникСсылка.Номенклатура станет ограничением.
В таких случаях рекомендуется использовать Табличные части у пользователя или механизм Дополнительных сведений. Если бы папки хранились в табличной части, запрос выглядел бы практически так же, но во вложенном подзапросе мы бы выбирали данные из этой табличной части:
ВЫБРАТЬ
Номенклатура.Ссылка
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
Номенклатура.Ссылка В ИЕРАРХИИ (
ВЫБРАТЬ
ТЧ_Папки.Папка
ИЗ
Справочник.Пользователи.ДоступныеПапки КАК ТЧ_Папки
ГДЕ
ТЧ_Папки.Ссылка = &Пользователь
)
Подводя итог, можно сказать, что решение через подзапрос в операторе В ИЕРАРХИИ является наиболее лаконичным и правильным с точки зрения функциональных возможностей платформы 1С v8.3. Оно полностью решает проблему "понедельника", позволяя одной командой получить все необходимые данные без избыточного кода на встроенном языке.