Как выбрать группы нижнего уровня иерархии в 1С с помощью запроса?

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

При работе с информационными системами часто возникает необходимость синхронизировать данные между 1С и внешними ресурсами, такими как FTP-серверы. Одним из таких сценариев является создание структуры папок на FTP, которая полностью или частично повторяет иерархию групп справочников в 1С. В нашем случае, мы сталкиваемся с задачей создания папок для групп справочника «Номенклатура». Однако, создание папок для всех групп подряд может быть неэффективным и избыточным, особенно если иерархия справочника очень глубока, а обновление структуры требуется периодически.

Давайте рассмотрим ситуацию: у нас есть справочник «Номенклатура» со следующей иерархией групп:

  1. Товары
  2.     Канцелярия
  3.         Карандаши
  4.         Ручки

Если мы будем создавать папки для всех групп, то получим: C:\1\, C:\1\2\, C:\1\2\3\, C:\1\2\4\. В то же время, для формирования полной структуры до самых глубоких уровней, нам достаточно создать папки только для «Карандашей» и «Ручек», так как пути к их родительским группам будут включены автоматически: C:\1\2\3\ и C:\1\2\4\. Таким образом, нам необходимо выбрать только те группы, которые находятся на самом «нижнем» уровне иерархии, то есть не имеют вложенных в себя других групп.

Это позволит нам значительно минимизировать количество операций при проверке и создании папок на FTP, оптимизируя процесс и уменьшая нагрузку. Мы проанализируем, как с помощью запроса 1С выбрать именно такие группы.

Понимание задачи: что такое «группа нижнего уровня»?

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

Рассмотрим предложенные примеры:

Основное решение: выборка групп нижнего уровня с помощью временной таблицы

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

Шаг 1: Помещаем все группы справочника во временную таблицу

Начнем с создания временной таблицы, которая будет содержать все группы справочника Номенклатура. Это позволит нам работать с ограниченным набором данных и упростит дальнейшие операции. Мы выбираем ссылку на группу (Ссылка) и ссылку на её родителя (Родитель).


ВЫБРАТЬ
    Номенклатура.Ссылка КАК Ссылка,
    Номенклатура.Родитель КАК Родитель
ПОМЕСТИТЬ ВТ_Группы
ИЗ
    Справочник.Номенклатура КАК Номенклатура
ГДЕ
    Номенклатура.ЭтоГруппа = ИСТИНА
;

В этом запросе:

Шаг 2: Отбираем группы, которые не являются родителями для других групп

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


////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ_Группы.Ссылка КАК Ссылка
ИЗ
    ВТ_Группы КАК ВТ_Группы
ГДЕ
    НЕ ВТ_Группы.Ссылка В
        (ВЫБРАТЬ
            ВТ_Группы.Родитель
        ИЗ
            ВТ_Группы)
;

Рассмотрим детали этого подзапроса:

Соединение этих двух частей позволяет нам получить список групп, которые не выступают в роли родителя ни для одной другой группы в иерархии. Именно это и есть наш искомый набор «групп нижнего уровня».

Почему некоторые другие подходы могут быть менее эффективными или некорректными?

В процессе поиска решения часто возникают другие идеи, которые, к сожалению, могут не дать нужного результата или быть неоптимальными. Например, попытка использовать ЛЕВОЕ СОЕДИНЕНИЕ для поиска родительских групп и фильтрации может привести к некорректной выборке. Если мы попытаемся найти группы, у которых нет дочерних групп, используя только ЛЕВОЕ СОЕДИНЕНИЕ, мы можем получить все группы, включая верхние, если не продумаем условия отбора достаточно тщательно. Пример такого ошибочного запроса:


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

Этот запрос, скорее всего, вернет все группы, а не только нижние. Причина в том, что условие Где Родители.ЭтоГруппа = ИСТИНА не помогает отсеять группы, которые *сами* являются родителями. Нам нужно условие, которое проверяет *отсутствие* дочерних элементов, а не просто принадлежность к группе. Более того, при использовании ЛЕВОЕ СОЕДИНЕНИЕ, если группа не имеет родителя (т.е. является группой верхнего уровня), поле Родители.Ссылка будет NULL, и условие Родители.ЭтоГруппа = ИСТИНА его отсечет. Это приведет к потере групп верхнего уровня, если они не являются родителями для *любых* групп, а также к потере групп, которые не имеют родителей.

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

Альтернативные подходы и трактовки

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

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


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

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

Заключение и преимущества предложенного решения

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

  1. Точен: Гарантированно возвращает только те группы, которые не являются родителями для других групп.
  2. Эффективен: Использование временной таблицы позволяет оптимизировать выполнение запроса, особенно на больших объемах данных, поскольку сначала фильтруются все группы, а затем выполняется подзапрос на меньшем наборе данных.
  3. Универсален: Подходит для любого справочника 1С, имеющего иерархическую структуру (с полями Ссылка и Родитель).

Используя этот запрос, мы сможем формировать минимально необходимый набор путей для создания папок на FTP, что значительно сократит время выполнения операции синхронизации и сделает процесс более устойчивым к ошибкам.

← На главную