При работе с информационными системами часто возникает необходимость синхронизировать данные между 1С и внешними ресурсами, такими как FTP-серверы. Одним из таких сценариев является создание структуры папок на FTP, которая полностью или частично повторяет иерархию групп справочников в 1С. В нашем случае, мы сталкиваемся с задачей создания папок для групп справочника «Номенклатура». Однако, создание папок для всех групп подряд может быть неэффективным и избыточным, особенно если иерархия справочника очень глубока, а обновление структуры требуется периодически.
Давайте рассмотрим ситуацию: у нас есть справочник «Номенклатура» со следующей иерархией групп:
Если мы будем создавать папки для всех групп, то получим: C:\1\, C:\1\2\, C:\1\2\3\, C:\1\2\4\. В то же время, для формирования полной структуры до самых глубоких уровней, нам достаточно создать папки только для «Карандашей» и «Ручек», так как пути к их родительским группам будут включены автоматически: C:\1\2\3\ и C:\1\2\4\. Таким образом, нам необходимо выбрать только те группы, которые находятся на самом «нижнем» уровне иерархии, то есть не имеют вложенных в себя других групп.
Это позволит нам значительно минимизировать количество операций при проверке и создании папок на FTP, оптимизируя процесс и уменьшая нагрузку. Мы проанализируем, как с помощью запроса 1С выбрать именно такие группы.
Прежде всего, давайте уточним, что мы подразумеваем под «группами нижнего уровня иерархии» или «самыми глубокими папками». В контексте нашей задачи, это группы справочника, которые не содержат в себе других групп. Они могут содержать элементы (товары, услуги) или быть пустыми, но ключевой критерий — отсутствие дочерних групп.
Рассмотрим предложенные примеры:
Для решения этой задачи мы воспользуемся запросом, который сначала соберет все группы справочника во временную таблицу, а затем отберет из этой таблицы только те группы, которые не являются родителями для каких-либо других групп, также находящихся в этой временной таблице. Этот подход является наиболее эффективным и часто применяемым для задач такого рода в 1С.
Начнем с создания временной таблицы, которая будет содержать все группы справочника Номенклатура. Это позволит нам работать с ограниченным набором данных и упростит дальнейшие операции. Мы выбираем ссылку на группу (Ссылка) и ссылку на её родителя (Родитель).
ВЫБРАТЬ
Номенклатура.Ссылка КАК Ссылка,
Номенклатура.Родитель КАК Родитель
ПОМЕСТИТЬ ВТ_Группы
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
Номенклатура.ЭтоГруппа = ИСТИНА
;
В этом запросе:
ВЫБРАТЬ указывает, какие поля мы хотим получить: Ссылка (уникальный идентификатор группы) и Родитель (ссылка на родительскую группу).ПОМЕСТИТЬ ВТ_Группы создает временную таблицу с именем ВТ_Группы, в которую будут помещены результаты запроса.ИЗ Справочник.Номенклатура КАК Номенклатура указывает, что данные берутся из справочника Номенклатура.ГДЕ Номенклатура.ЭтоГруппа = ИСТИНА является критически важным условием, которое отбирает только элементы, являющиеся группами справочника, исключая обычные элементы номенклатуры.Теперь, когда у нас есть временная таблица со всеми группами и их родителями, мы можем выполнить основной отбор. Нам нужны группы, чья Ссылка не встречается в поле Родитель ни у одной из других групп в этой же временной таблице. Это означает, что для текущей группы нет дочерних групп.
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_Группы.Ссылка КАК Ссылка
ИЗ
ВТ_Группы КАК ВТ_Группы
ГДЕ
НЕ ВТ_Группы.Ссылка В
(ВЫБРАТЬ
ВТ_Группы.Родитель
ИЗ
ВТ_Группы)
;
Рассмотрим детали этого подзапроса:
ВЫБРАТЬ ВТ_Группы.Ссылка КАК Ссылка указывает, что мы хотим получить ссылки на группы из нашей временной таблицы ВТ_Группы.ГДЕ НЕ ВТ_Группы.Ссылка В (...) является ключевым. Оно означает: "выбрать те группы, чья собственная ссылка не присутствует в списке ссылок на родителей других групп".(ВЫБРАТЬ ВТ_Группы.Родитель ИЗ ВТ_Группы) формирует список всех ссылок на родительские группы, которые есть в нашей временной таблице. То есть, этот список содержит ссылки на все группы, у которых есть хотя бы одна дочерняя группа.Соединение этих двух частей позволяет нам получить список групп, которые не выступают в роли родителя ни для одной другой группы в иерархии. Именно это и есть наш искомый набор «групп нижнего уровня».
В процессе поиска решения часто возникают другие идеи, которые, к сожалению, могут не дать нужного результата или быть неоптимальными. Например, попытка использовать ЛЕВОЕ СОЕДИНЕНИЕ для поиска родительских групп и фильтрации может привести к некорректной выборке. Если мы попытаемся найти группы, у которых нет дочерних групп, используя только ЛЕВОЕ СОЕДИНЕНИЕ, мы можем получить все группы, включая верхние, если не продумаем условия отбора достаточно тщательно. Пример такого ошибочного запроса:
ВЫБРАТЬ
Группы.Ссылка
ИЗ
Справочник.Номенклатура КАК Группы
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Родители
ПО Группы.Родитель = Родители.Ссылка
ГДЕ
Родители.ЭтоГруппа = ИСТИНА
И Группы.ЭтоГруппа = ИСТИНА
;
Этот запрос, скорее всего, вернет все группы, а не только нижние. Причина в том, что условие Где Родители.ЭтоГруппа = ИСТИНА не помогает отсеять группы, которые *сами* являются родителями. Нам нужно условие, которое проверяет *отсутствие* дочерних элементов, а не просто принадлежность к группе. Более того, при использовании ЛЕВОЕ СОЕДИНЕНИЕ, если группа не имеет родителя (т.е. является группой верхнего уровня), поле Родители.Ссылка будет NULL, и условие Родители.ЭтоГруппа = ИСТИНА его отсечет. Это приведет к потере групп верхнего уровня, если они не являются родителями для *любых* групп, а также к потере групп, которые не имеют родителей.
Подход с временной таблицей и подзапросом, предложенный выше, явно и однозначно отсекает все группы, которые встречаются в списке родительских групп, что точно соответствует нашему определению «групп нижнего уровня».
Важно отметить, что иногда под «группами нижнего уровня» могут подразумеваться группы, в которых непосредственно хранятся элементы (номенклатурные позиции, услуги и т.д.), а не группы, не имеющие дочерних групп. Если ваша задача заключается именно в этом, то подход к запросу будет немного иным.
В таком случае, мы могли бы сначала выбрать все элементы (не группы) справочника, а затем получить ссылки на их родительские группы. Это позволило бы нам получить список групп, которые реально используются для хранения позиций. Однако, такой запрос не гарантирует, что эти группы будут именно «самыми глубокими» в иерархии групп. Например, элемент может лежать в группе «Канцелярия», даже если у «Канцелярии» есть подгруппы («Карандаши», «Ручки»). Если же элементы могут находиться только в самых нижних группах, то этот метод будет работать аналогично нашему основному решению.
ВЫБРАТЬ РАЗЛИЧНЫЕ
Номенклатура.Родитель КАК СсылкаНаГруппу
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
Номенклатура.ЭтоГруппа = ЛОЖЬ
;
Этот запрос выбирает всех родителей для элементов номенклатуры. Если элементам разрешено храниться только в группах, у которых нет подгрупп, то этот запрос будет эквивалентен предыдущему. Однако, если элементы могут храниться в группах любого уровня, этот запрос может вернуть и родительские группы, которые не являются «нижними» по критерию отсутствия подгрупп.
Предложенный нами запрос с использованием временной таблицы является наиболее точным и эффективным способом выбрать группы нижнего уровня иерархии в 1С по критерию «не имеющие вложенных групп». Этот подход:
Ссылка и Родитель).Используя этот запрос, мы сможем формировать минимально необходимый набор путей для создания папок на FTP, что значительно сократит время выполнения операции синхронизации и сделает процесс более устойчивым к ошибкам.