Как получить всю номенклатуру из папки, указанной в реквизите пользователя, с учетом иерархии

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

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

Рассмотрим детально, как решить эту задачу максимально эффективно, разберем типичные ошибки и проанализируем поведение системы при различных подходах.

Вариант 1. Использование конструкции В ИЕРАРХИИ с подзапросом

Многие начинающие разработчики полагают, что оператор В ИЕРАРХИИ может принимать только внешние параметры, переданные из встроенного языка. Однако, начиная с версии платформы 8.2, система официально поддерживает использование подзапросов внутри этого оператора. Это позволяет решить задачу буквально в одно предложение.

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


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

В данном примере система сначала выполнит вложенный запрос к справочнику Пользователи, получит ссылку на группу номенклатуры, а затем использует её как корень для построения иерархического списка. Важно отметить, что если в реквизите ПапкаНоменклатуры будет пустое значение или NULL, запрос вернет пустой результат, что является ожидаемым поведением.

Вариант 2. Использование временных таблиц для оптимизации

Несмотря на изящность первого варианта, с точки зрения производительности СУБД (особенно на больших объемах данных) использование временных таблиц часто оказывается предпочтительным. Рассмотрим, почему это так. Когда мы используем подзапрос непосредственно в условии ГДЕ, планировщик запросов СУБД не всегда может оптимально построить план выполнения, особенно если иерархия справочника Номенклатура имеет большую глубину.

Разберем по шагам создание запроса с использованием временной таблицы:

  1. Сначала мы извлекаем нужную папку из справочника пользователей и помещаем её в отдельную временную таблицу.
  2. Затем мы выбираем данные из справочника номенклатуры, используя иерархическое сравнение с данными из этой временной таблицы.

// Шаг 1: Получаем целевую папку во временную таблицу
ВЫБРАТЬ
    Пользователи.ПапкаНоменклатуры КАК ЦелеваяПапка
ПОМЕСТИТЬ ВТ_ПапкаПользователя
ИЗ
    Справочник.Пользователи КАК Пользователи
ГДЕ
    Пользователи.Ссылка = &Пользователь
;

////////////////////////////////////////////////////////////////////////////////
// Шаг 2: Выбираем иерархию номенклатуры
ВЫБРАТЬ
    Номенклатура.Ссылка КАК Ссылка
ИЗ
    Справочник.Номенклатура КАК Номенклатура
ГДЕ
    Номенклатура.Ссылка В ИЕРАРХИИ (
        ВЫБРАТЬ
            ВТ_ПапкаПользователя.ЦелеваяПапка
        ИЗ
            ВТ_ПапкаПользователя КАК ВТ_ПапкаПользователя
    )

Такой подход позволяет платформе 1С более явно сформировать инструкции для SQL-сервера. Это особенно актуально, если запрос является частью сложного отчета или динамического списка.

Анализ типичных ошибок: Соединение по Родителю

Иногда предлагается использовать ЛЕВОЕ СОЕДИНЕНИЕ по условию Номенклатура.Родитель = Пользователь.ПапкаНоменклатуры. Давайте выясним причину, по которой этот метод не является решением поставленной задачи.

Проблема заключается в том, что условие по равенству родителя выбирает только первый уровень вложенности. Если внутри целевой папки "Продукты" есть подпапка "Молочные продукты", а в ней — "Кефир", то при обычном соединении по родителю "Кефир" в выборку не попадет. Оператор В ИЕРАРХИИ — это единственный способ в языке запросов 1С автоматически обойти все уровни дерева без написания рекурсивных алгоритмов на встроенном языке.

Особенности работы с большими справочниками

При использовании иерархических запросов важно помнить о следующих технических аспектах:

Альтернативный взгляд: Дизайн структуры данных

В ходе обсуждения подобных задач часто возникает вопрос: насколько рационально хранить ограничение доступа или фильтрацию через одну папку? Если одному пользователю нужно видеть номенклатуру из разных папок, жесткая привязка к одному реквизиту типа СправочникСсылка.Номенклатура станет ограничением.

В таких случаях рекомендуется использовать Табличные части у пользователя или механизм Дополнительных сведений. Если бы папки хранились в табличной части, запрос выглядел бы практически так же, но во вложенном подзапросе мы бы выбирали данные из этой табличной части:


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

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

← На главную