Как решить задачу иерархического обхода в консоли запросов 1С без использования СКД и кода?

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

В практике разработчика 1С иногда возникают «спортивные» задачи или требования на собеседованиях, когда необходимо построить отчет по иерархическому справочнику произвольной вложенности, используя исключительно Консоль запросов. Сложность заключается в том, что язык запросов 1С не поддерживает рекурсивные вызовы (конструкции типа WITH RECURSIVE в SQL), а стандартный механизм СКД, который легко справляется с иерархией, по условию задачи использовать нельзя.

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

Почему задача считается сложной?

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

Рассмотрим ситуацию: у нас есть справочник Подразделения с неограниченным уровнем вложенности. Нам нужно получить данные из регистра, привязанные к нижним узлам, но сгруппировать их по всем вышестоящим родителям. Если уровень вложенности равен 2 или 3, мы можем просто написать несколько левых соединений. Но что делать, если уровней 10, 20 или 99?

Метод бинарного возведения (Binary Doubling)

Проанализируем наиболее эффективный способ решения — алгоритм бинарного удвоения. Суть метода заключается в том, что каждое последующее соединение таблиц позволяет нам увеличить глубину просматриваемой иерархии в геометрической прогрессии. Если в первом запросе мы соединяем элемент с его непосредственным кратким родителем (1 уровень), то во втором шаге мы можем соединить результат с самим собой, получив уже 2 уровня, затем 4, 8, 16 и так далее.

Разберем по шагам, как это реализовать в пакете запросов:

  1. Создание базовой таблицы связей: Сначала мы выбираем все элементы справочника и их непосредственных родителей. Это наш «фундамент».
  2. Итерационное расширение: Мы создаем временную таблицу, в которой соединяем таблицу связей саму с собой по принципу: Т1.Родитель = Т2.Ссылка.
  3. Геометрический рост: Каждое такое соединение в пакете удваивает доступную глубину. Чтобы покрыть иерархию в 1024 уровня (что практически невероятно для реальных бизнес-данных), нам потребуется всего 10 подобных шагов в одном пакете запросов.

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


// Шаг 1: Получаем прямые связи
ВЫБРАТЬ
    Подразделения.Ссылка КАК Элемент,
    Подразделения.Родитель КАК Родитель
ПОМЕСТИТЬ ТЗ_Связи_L1
ИЗ
    Справочник.Подразделения КАК Подразделения;

////////////////////////////////////////////////////////////////////////////////
// Шаг 2: Удваиваем глубину (до 2-х уровней)
ВЫБРАТЬ
    T1.Элемент КАК Элемент,
    ЕСТЬNULL(T2.Родитель, T1.Родитель) КАК Родитель
ПОМЕСТИТЬ ТЗ_Связи_L2
ИЗ
    ТЗ_Связи_L1 КАК T1
        ЛЕВОЕ СОЕДИНЕНИЕ ТЗ_Связи_L1 КАК T2
        ПО T1.Родитель = T2.Элемент;

Продолжая эту логику, в таблице ТЗ_Связи_L3 мы получим связи через 4 колена, в L4 — через 8 и так далее. Это позволяет нам «пробить» любую глубину вложенности, не зная её заранее.

Использование транзитивного замыкания

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

  1. Мы берем данные из регистра (например, обороты или остатки) и соединяем их с нашей расширенной таблицей иерархии. При избыточном объеме исторических записей в 1С:ERP для повышения производительности может применяться многопоточная свёртка базы для очистки регистров.
  2. Соединение идет по полю Подразделение (из регистра) = Элемент (из нашей иерархической таблицы).
  3. В итоговую выборку мы выводим поле Родитель из иерархической таблицы и суммируем ресурсы регистра.
  4. Группируем результат по полю Родитель.

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

Важные нюансы при работе в консоли

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

Иерархия элементов vs Иерархия групп: Если в справочнике используется иерархия элементов (как в случае с подразделениями), количество записей во временных таблицах будет равно общему количеству элементов. Это может создать нагрузку на tempdb СУБД. Рекомендуется выбирать только те поля, которые необходимы для связи (Ссылка и Родитель), используя тип УникальныйИдентификатор или ссылку.

Ограничение В ИЕРАРХИИ: Помним, что в консоли запросов мы не можем написать ГДЕ Таблица1.Ссылка В ИЕРАРХИИ (Таблица2.Ссылка). Это фундаментальное ограничение. Именно поэтому метод бинарного удвоения через ЛЕВОЕ СОЕДИНЕНИЕ является единственным рабочим способом «честного» решения задачи без использования программного кода.

Выясним причину: почему это решение лучше «плоских» соединений?

Если мы будем просто соединять таблицу 100 раз подряд (L1 с L2, L2 с L3...), запрос получится избыточным и крайне медленным. Метод бинарного возведения (L1+L1=L2, L2+L2=L4) работает за логарифмическое время относительно глубины иерархии. Это позволяет сохранять производительность даже на больших справочниках, особенно если настроено автоматическое обслуживание и тестирование баз 1С в тихом режиме.

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

← На главную