Пример получения в запросе всех подразделений с учётом иерархии (неограниченный уровень вложенности подразделений)

17.02.12

Разработка - Запросы

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

Постановка задачи : имеется регистр сведений опЗапретПремированияПодразделений, в который введены подразделения, запрещённые к премированию. В этом регистре есть измерения Организация и ПодразделениеОрганизации, а также ресурсы ПремированиеРазрешено и СУчетомИерархии.

Требуется : получить все запрещённые к премированию подразделения.

Решение задачи :

1) Получить из регистра сведений срез всех запрещённых подразделений по организации, поместить результат во временную таблицу ЗапрещенныеПодразделения1.

2) Посчитать количество полученных подразделений. N = 1.

3) Соединить полученную таблицу подразделений ЗапрещенныеПодразделенияN со всей таблицей подразделений ПодразделенияОрганизаций по условию ЗапрещенныеПодразделения.ПодразделениеОрганизации = ПодразделенияОрганизаций.Родитель, тем самым получить всех потомков первого уровня всех найденных ранее подразделений.

4) Объединить результат п.3 с ранее полученной таблицей, исключив совпадения. Результат объединения поместить во временную таблицу ЗапрещенныеПодразделения(N+1) .

5) Посчитать количество полученных в п.4 подразделений.
Если оно совпадает с количеством подразделений, полученных на предыдущем шаге (т.е. в таблице ЗапрещенныеПодразделенияN), то завершить работу, выдав в качестве ответа колонку ПодразделениеОрганизации последней (или предпоследней!) временной таблицы.
В противном случае увеличить N на единицу и перейти к п.3.

// получает все запрещенные к премированию подразделения с учетом иерархии
Функция ПолучитьВсеЗапрещенныеПодразделения(Организация, ДатаОтчета)

    МВТ = Новый МенеджерВременныхТаблиц;

   
Запрос = Новый Запрос();
   
Запрос.МенеджерВременныхТаблиц = МВТ;

   
// 1) сначала получим сырые данные

   
Запрос.Текст = "ВЫБРАТЬ
    |   опЗапретПремированияПодразделенийСрезПоследних.СУчетомИерархии,
    |   опЗапретПремированияПодразделенийСрезПоследних.ПодразделениеОрганизации
    |ПОМЕСТИТЬ ЗапрещенныеПодразделения1
    |ИЗ
    |   РегистрСведений.опЗапретПремированияПодразделений.СрезПоследних(&ДатаСреза, Организация = &Организация) КАК опЗапретПремированияПодразделенийСрезПоследних
    |ГДЕ
    |   НЕ опЗапретПремированияПодразделенийСрезПоследних.ПремированиеРазрешено"
;

   
Запрос.УстановитьПараметр("Организация", Организация);
   
Запрос.УстановитьПараметр("ДатаСреза", КонецДня(ДатаОтчета));

    Результат = Запрос.Выполнить();
   
Выборка = Результат.Выбрать();

   
Выборка.Следующий();

   
// 2) получим количество записей временной таблицы
   
КолВоЗаписей1 = Выборка.Количество;

   
КолВоЗаписей2 = 0;

   
НомерЦикла1 = 1;

   
// 3) затем напишем циклический запрос, в котором будут меняться номера вложенных таблиц

    // 4) всё время результат будем объединять с исходной таблицей (без совпадений!)

   
Запрос.Текст = "ВЫБРАТЬ
    |   ЗапрещенныеПодразделения.СУчетомИерархии,
    |   ПодразделенияОрганизаций.Ссылка КАК ПодразделениеОрганизации
    |ПОМЕСТИТЬ ЗапрещенныеПодразделения1
    |ИЗ
    |   ЗапрещенныеПодразделения0 КАК ЗапрещенныеПодразделения
    |       ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ПодразделенияОрганизаций КАК ПодразделенияОрганизаций
    |       ПО ЗапрещенныеПодразделения.ПодразделениеОрганизации = ПодразделенияОрганизаций.Родитель
    |           И (ЗапрещенныеПодразделения.СУчетомИерархии)
    |
    |ОБЪЕДИНИТЬ
    |
    |ВЫБРАТЬ
    |   ЗапрещенныеПодразделения.СУчетомИерархии,
    |   ЗапрещенныеПодразделения.ПодразделениеОрганизации
    |ИЗ
    |   ЗапрещенныеПодразделения0 КАК ЗапрещенныеПодразделения"
;

   
// условие выхода из цикла - количество искомых подразделений перестанет расти

   
Пока КолВоЗаписей1 <> КолВоЗаписей2 Цикл

       
КолВоЗаписей2 = КолВоЗаписей1;

       
// циклически заменяем номера вложенных таблиц

       
Запрос.Текст = СтрЗаменить(Запрос.Текст, "ЗапрещенныеПодразделения" + НомерЦикла1, "ЗапрещенныеПодразделения" + Число(НомерЦикла1 + 1));
       
Запрос.Текст = СтрЗаменить(Запрос.Текст, "ЗапрещенныеПодразделения" + Число(НомерЦикла1 - 1), "ЗапрещенныеПодразделения" + НомерЦикла1);

       
Результат = Запрос.Выполнить();
       
Выборка = Результат.Выбрать();

       
Выборка.Следующий();

       
// 5) получим количество записей временной таблицы
       
КолВоЗаписей1 = Выборка.Количество;

       
НомерЦикла1 = НомерЦикла1 + 1;

    КонецЦикла;

   
// последняя (или предпоследняя!) таблица даст нужный результат, в колонке "ПодразделениеОрганизации"

    // последняя таблица имеет номер НомерЦикла1 (он только что был увеличен на 1)
    // предпоследняя таблица имеет номер (НомерЦикла1-1)

   
Запрос.Текст = "ВЫБРАТЬ
    |   ЗапрещенныеПодразделения.СУчетомИерархии,
    |   ЗапрещенныеПодразделения.ПодразделениеОрганизации
    |ИЗ
    |   ЗапрещенныеПодразделения0 КАК ЗапрещенныеПодразделения"
;

   
Запрос.Текст = СтрЗаменить(Запрос.Текст, "ЗапрещенныеПодразделения0", "ЗапрещенныеПодразделения" + НомерЦикла1);
   
Результат = Запрос.Выполнить();

    Возврат
Результат.Выгрузить().ВыгрузитьКолонку("ПодразделениеОрганизации");

КонецФункции
// ПолучитьВсеЗапрещенныеПодразделения()

.

Легко видеть, что этот код работает при любом уровне вложенности подразделений.

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

Этот код будет корректно работать, даже если в справочнике будут некорректные данные (явные ошибки в базе данных), например, когда подразделение-родитель является потомком своего потомка.

См. также

Инструментарий разработчика Роли и права Запросы СКД Программист Платформа 1С v8.3 Управляемые формы Запросы Система компоновки данных Конфигурации 1cv8 Платные (руб)

Набор инструментов программиста и специалиста 1С для всех конфигураций на управляемых формах. В состав входят инструменты: Консоль запросов, Консоль СКД, Консоль кода, Редактор объекта, Анализ прав доступа, Метаданные, Поиск ссылок, Сравнение объектов, Все функции, Подписки на события и др. Редактор запросов и кода с раскраской и контекстной подсказкой. Доработанный конструктор запросов тонкого клиента. Продукт хорошо оптимизирован и обладает самым широким функционалом среди всех инструментов, представленных на рынке.

10000 руб.

02.09.2020    141505    777    391    

804

Математика и алгоритмы Запросы Программист Платформа 1С v8.3 Запросы Бесплатно (free)

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

08.07.2024    1584    ivanov660    9    

21

Запросы СКД Программист Стажер Система компоновки данных Россия Бесплатно (free)

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

15.05.2024    5403    implecs_team    6    

44

Запросы Программист Стажер Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Часто поступают задачи по произвольному распределению общих сумм. После распределения иногда пропадают копейки. Суть решения добавить АвтоНомерЗаписи() в ВТ распределения, и далее используя функции МАКСИМУМ или МИНИМУМ можем положить разницу копеек в первую или последнюю строку знаменателя распределения.

11.04.2024    2981    andrey_sag    10    

35

Запросы СКД Программист Стажер Платформа 1С v8.3 Запросы Система компоновки данных 1С:ERP Управление предприятием 2 Бесплатно (free)

В типовых конфигурациях разработчики компании 1С иногда используют в отчетах, построенных на СКД, такую конструкцию, как "ГДЕ ЛОЖЬ". Такая конструкция говорит о том, что данные в запросе не будут получены совсем. Для чего же нужен тогда запрос?

13.02.2024    6802    KawaNoNeko    23    

26

Запросы СКД Программист Платформа 1С v8.3 Управляемые формы Конфигурации 1cv8 Абонемент ($m)

Есть список полей в виде текста, или запрос - закидываем в набор СКД.

1 стартмани

31.01.2024    2634    2    Yashazz    0    

33

Инструментарий разработчика Запросы Программист Стажер Платформа 1С v8.3 Управляемые формы Конфигурации 1cv8 Бесплатно (free)

Пишем на человеческом языке, что нам надо, и получаем текст запроса на языке 1С. Используются большие языковые модели (LLM GPT) от OpenAI или Яндекс на выбор.

15.01.2024    8460    90    mkalimulin    32    

60
Вознаграждение за ответ
Показать полностью
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. RailMen 824 10.09.12 18:51 Сейчас в теме
Жутко неоптимально :evil:
Совет: книги по основам программирования в 1С и оптимизации запросов.
+
минимальные требования для сдачи экзамена 1С:Специалист по платформе.
2. prodines 107 20.11.13 12:33 Сейчас в теме
А если так?

Запрос.Текст = "ВЫБРАТЬ
| опЗапретПремированияПодразделенийСрезПоследних.СУчетомИерархии,
| опЗапретПремированияПодразделенийСрезПоследних.ПодразделениеОрганизации
|ИЗ
| РегистрСведений.опЗапретПремированияПодразделений.СрезПоследних(&ДатаСреза, Организация = &Организация) КАК опЗапретПремированияПодразделенийСрезПоследних
|ГДЕ
| НЕ опЗапретПремированияПодразделенийСрезПоследних.ПремированиеРазрешено";

Запрос.УстановитьПараметр("Организация", Организация);
Запрос.УстановитьПараметр("ДатаСреза", КонецДня(ДатаОтчета));

Результат = Запрос.Выполнить();

МассивПодразделенийВерхнегоУровня = Результат.Выгрузить().ВыгрузитьКолонку("ПодразделениеОрганизации");
Показать


Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПодразделенияОрганизаций.Ссылка КАК Подразделение
|ИЗ
| Справочник.ПодразделенияОрганизаций КАК ПодразделенияОрганизаций
|ГДЕ
| ПодразделенияОрганизаций.Ссылка В ИЕРАРХИИ(&МассивПодразделенийВерхнегоУровня)";

Запрос.УстановитьПараметр("МассивПодразделенийВерхнегоУровня",МассивПодразделенийВерхнегоУровня);

Результат = Запрос.Выполнить();
megatrend; +1 Ответить
3. megatrend 130 20.11.13 12:42 Сейчас в теме
(2) prodines, всё гениальное просто :)
4. ildarovich 7899 21.11.14 13:15 Сейчас в теме
В статье Уровни, глубина, прародители, циклы и аналоги запросом в Примере 3 показан другой (более быстрый и компактный?) метод решения той же задачи. У него есть определенное сходство с методом, приведенным здесь, но там не множество достижимости на каждом шаге наращивается, а в одной таблице накапливаются связи родитель - потомок, причем на каждом этапе охват длины связей вырастает вдвое. За счет этого нужно при 100 уровнях не 100 соединений сделать, а всего 7.
Оставьте свое сообщение