Как реализовать соединение таблиц по иерархии в запросах и СКД 1С?

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

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

Почему нельзя использовать В ИЕРАРХИИ в условии соединения?

Проанализируем техническую сторону вопроса. Оператор В ИЕРАРХИИ в языке запросов 1С является «синтаксическим сахаром». На уровне СУБД (SQL Server, PostgreSQL и др.) такой команды не существует. Когда платформа встречает это условие в секции ГДЕ, она преобразует его в сложный подзапрос или серию условий, выбирающих все идентификаторы (GUID) элементов и их потомков. Реализовать подобную логику внутри операции JOIN (соединение) крайне затруднительно с точки зрения производительности и логики построения плана запроса SQL. Поэтому попытка написать ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Пользователи ПО Регистр.Группа = Пользователи.Ссылка В ИЕРАРХИИ приведет к синтаксической ошибке.

Решение 1: Связи наборов данных в СКД (рекомендуемый способ)

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

Шаг 1. Создадим первый набор данных (НаборДанных1). Это будет запрос к нашему регистру сведений, где хранятся группы и проценты:


ВЫБРАТЬ
    РегистрПроцентов.ГруппаПользователей КАК Группа,
    РегистрПроцентов.Процент КАК Процент
ИЗ
    РегистрСведений.НастройкиПроцентов КАК РегистрПроцентов

Шаг 2. Создадим второй набор данных (НаборДанных2). Это будет запрос к справочнику пользователей, который мы будем фильтровать:


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

Шаг 3. Настроим связи наборов данных. Перейдем на вкладку «Связи наборов данных» и добавим новую связь:

  1. Источник связи: НаборДанных1.
  2. Приемник связи: НаборДанных2.
  3. Условие связи: Группа (из источника) соединяется с параметром &ГруппаИзРегистра (в приемнике).

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

Решение 2: Использование оператора В ИЕРАРХИИ в секции ГДЕ

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


ВЫБРАТЬ
    Пользователи.Ссылка КАК Пользователь
ИЗ
    Справочник.Пользователи КАК Пользователи
ГДЕ
    Пользователи.Ссылка В ИЕРАРХИИ (ВЫБРАТЬ Т.Пользователь ИЗ РегистрСведений.ВашРег КАК Т)

Проанализируем этот запрос. Он успешно выберет всех подчиненных пользователей. Однако мы не сможем вытащить поле Процент из регистра для каждого конкретного пользователя в этом же запросе, так как здесь нет соединения. Этот способ хорош только для фильтрации «сверху вниз» без сопоставления значений из двух таблиц.

Решение 3: «Плоское» соединение через фиксированное количество уровней

Если вы точно знаете, что иерархия в вашем справочнике ограничена (например, не более 3-4 уровней), можно прибегнуть к методу множественных соединений. Рассмотрим пример, когда мы соединяем справочник с регистром по родителю или родителю родителя:


ВЫБРАТЬ
    Пользователи.Ссылка КАК Пользователь,
    ЕСТЬNULL(Рег1.Процент, ЕСТЬNULL(Рег2.Процент, Рег3.Процент)) КАК Процент
ИЗ
    Справочник.Пользователи КАК Пользователи
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ВашРег КАК Рег1 
        ПО Пользователи.Родитель = Рег1.Пользователь
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ВашРег КАК Рег2 
        ПО Пользователи.Родитель.Родитель = Рег2.Пользователь
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ВашРег КАК Рег3 
        ПО Пользователи.Родитель.Родитель.Родитель = Рег3.Пользователь

Хотя этот метод кажется громоздким и «некрасивым», он работает очень быстро и не требует использования СКД. Мы просто перебираем возможные уровни вложенности. Однако помните, что при появлении нового уровня иерархии запрос придется переписывать. Для автоматического построения таких конструкций можно использовать инструмент для формирования текста запроса с получением родителей всех уровней справочника.

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

В современных конфигурациях 1С (на базе БСП, таких как УТ 11, ERP, КА) разработчики часто уходят от иерархических справочников в пользу отдельных регистров сведений, хранящих состав групп. Если же в вашей базе такого регистра нет, вы можете создать временную таблицу «всех потомков» программно. В системах 1С:ERP для сокращения объема данных и ускорения выполнения запросов предусмотрена многопоточная свёртка 1С:ERP в несколько параллельных потоков.

Разберем логику:

  1. Выбираем все группы из регистра во временную таблицу.
  2. Для каждой группы получаем список всех ее элементов (через ВыгрузитьИерархию() или аналогичные методы в коде).
  3. Помещаем этот развернутый список во вторую временную таблицу запроса.
  4. Соединяем основную таблицу с этой временной таблицей обычным ЛЕВОЕ СОЕДИНЕНИЕ.

Сравнение методов и производительность

Выясним, какой метод выбрать в зависимости от ситуации:

Важный момент: всегда помните о производительности. Оператор В ИЕРАРХИИ создает нагрузку на СУБД, так как требует рекурсивного обхода дерева данных. Если в вашем регистре тысячи групп, а в справочнике десятки тысяч пользователей, используйте только индексированные поля для связей и старайтесь максимально ограничивать выборку перед соединением.

← На главную