Обход группировок по иерархии

31.03.15

Разработка - Механизмы платформы 1С

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

«Подводные камни», мешающие реализовать обход иерархии:

1)      В запросе в итогах нужно использовать ключевое слово ИЕРАРХИЯ, например, «ИТОГИ ПО Номенклатура Иерархия»

2)      При использовании Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией) ,если есть несколько уровней группировки, нужно указывать второй параметр, строку с именем поля группировки. Например, для иерархической группироки по номенклатуре правильно будет Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией, «Номенклатура»)

3)      При обходе выборки мы можем находиться в текущий момент на элементе или папке, для папки необходимо запускать рекурсивно выборку элементов в этой папке. А для элемента нижестоящую выборку, если есть группировки в запросе ниже нашей иерархической группировки, либо ничего не делать, если наша группировка нижняя. Чтобы определить тип элемента, используется функция ТипЗаписи()

Сам алгоритм обхода.

1)      Без иерархии

Выборка1 = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам); 
Пока Выборка1.Следующий() Цикл
  // Вставить обработку выборки Выборка1
  Выборка2 = Выборка1.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
  Пока Выборка2.Следующий() Цикл
    // Вставить обработку выборки Выборка2
    ОбработатьЭлемент();
  КонецЦикла;
КонецЦикла;

2)      Иерархия на первом уровне группировки, второй уровень без иерархии

           

ВыборкаСИерархией = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией,"Номенклатура");
ВыбратьЭлементыВИерархии(ВыборкаСИерархией);
 
Процедура ВыбратьЭлементыВИерархии(ВыборкаСИерархией)
  Пока ВыборкаСИерархией.Следующий() Цикл
    Если ВыборкаСИерархией.ТипЗаписи()=ТипЗаписиЗапроса.ИтогПоИерархии Тогда
      ВыбратьЭлементыВИерархии (ВыборкаСИерархией.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией,"Номенклатура"));
    ИначеЕсли ВыборкаСИерархией.ТипЗаписи()=ТипЗаписиЗапроса.ИтогПоГруппировке Тогда
      ВыбратьЭлементыБезИерархии (ВыборкаСИерархией.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам));
    КонецЕсли;   
  КонецЦикла;
КонецПроцедуры
 
Процедура ВыбратьЭлементыБезИерархии (ВыборкаБезИерархии)
  Пока ВыборкаБезИерархии.Следующий() Цикл
    // Вставить обработку выборки ВыборкаБезИерархии
    ОбработатьЭлемент();
  КонецЦикла;
КонецПроцедуры

 

3) Первый уровень без иерархии, второй с иерархией

ВыборкаБезИерахии = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);       
Пока ВыборкаБезИерахии.Следующий() Цикл
  // Вставить обработку выборки ВыборкаБезИерахии
  ВыборкаСИерархией = ВыборкаБезИерахии.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией,"Номенклатура"));
  ВыбратьЭлементыВИерархии(ВыборкаСИерархией);
КонецЦикла;
 
Процедура ВыбратьЭлементыВИерархии(ВыборкаСИерархией)
  Пока ВыборкаСИерархией.Следующий() Цикл
    Если ВыборкаСИерархией.ТипЗаписи()=ТипЗаписиЗапроса.ИтогПоИерархии Тогда
      ВыбратьЭлементыВИерархии (ВыборкаСИерархией.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией,"Номенклатура"));
    ИначеЕсли ВыборкаСИерархией.ТипЗаписи()=ТипЗаписиЗапроса. ДетальнаяЗапись Тогда
      ОбработатьЭлемент();
    КонецЕсли;   
  КонецЦикла;
КонецПроцедуры

4) Первый уровень без иерархии, второй с иерархией (без рекурсии)

    ВыборкаНоменклатура = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией,"Номенклатура");
    
    Стек = Новый Массив ( 200 );
    КоличествоВСтеке=0;
    Выход=Не ВыборкаНоменклатура.Следующий();
    
    Пока Не Выход Цикл
        Пока ВыборкаНоменклатура.ТипЗаписи()=ТипЗаписиЗапроса.ИтогПоИерархии Цикл
            Стек[КоличествоВСтеке]=ВыборкаНоменклатура;
            КоличествоВСтеке=КоличествоВСтеке+1;
            // Обработка папки
            Сообщить(ВыборкаНоменклатура.Номенклатура);
            ВыборкаНоменклатура=ВыборкаНоменклатура.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией,"Номенклатура");
            ВыборкаНоменклатура.Следующий();
        КонецЦикла;
        // Обработка элемента
        Сообщить(ВыборкаНоменклатура.Номенклатура);
        // Обработка следующей группировки
        ВыбратьДанные(ВыборкаНоменклатура.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам));
        ЕстьСледующий= ВыборкаНоменклатура.Следующий();
        Пока Не ЕстьСледующий И КоличествоВСтеке>0 Цикл
            КоличествоВСтеке=КоличествоВСтеке-1;
            ВыборкаНоменклатура=Стек[КоличествоВСтеке];
            ЕстьСледующий= ВыборкаНоменклатура.Следующий();
        КонецЦикла;
        Если Не ЕстьСледующий И КоличествоВСтеке=0 Тогда
            Выход=Истина;
        КонецЕсли;
    КонецЦикла;



иерархия обход

См. также

Поинтегрируем: сервисы интеграции – новый стандарт или просто коннектор?

Обмен между базами 1C Администрирование СУБД Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

В платформе 8.3.17 появился замечательный механизм «Сервисы интеграции». Многие считают, что это просто коннектор 1С:Шины. Так ли это?

11.03.2024    4434    dsdred    53    

70

Как готовить и есть массивы

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

Все мы используем массивы в своем коде. Это один из первых объектов, который дают ученикам при прохождении обучения программированию. Но умеем ли мы ими пользоваться? В этой статье я хочу показать все методы массива, а также некоторые фишки в работе с массивами.

24.01.2024    5272    YA_418728146    25    

62

Планы обмена VS История данных

Обмен между базами 1C Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

Вы все еще регистрируете изменения только на Планах обмена и Регистрах сведений?

11.12.2023    6391    dsdred    36    

111

1С-ная магия

Механизмы платформы 1С Бесплатно (free)

Язык программирования 1С содержит много нюансов и особенностей, которые могут приводить к неожиданным для разработчика результатам. Сталкиваясь с ними, программист начинает лучше понимать логику платформы, а значит, быстрее выявлять ошибки и видеть потенциальные узкие места своего кода там, где позже можно было бы ещё долго медитировать с отладчиком в поисках источника проблемы. Мы рассмотрим разные примеры поведения кода 1С. Разберём результаты выполнения и ответим на вопросы «Почему?», «Как же так?» и «Зачем нам это знать?». 

06.10.2023    18464    SeiOkami    46    

118

Дефрагментация и реиндексация после перехода на платформу 8.3.22

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

Начиная с версии платформы 8.3.22 1С снимает стандартные блокировки БД на уровне страниц. Делаем рабочий скрипт, как раньше.

14.09.2023    12074    human_new    27    

74

Валидация JSON через XDTO (включая массивы)

WEB-интеграция Универсальные функции Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

При работе с интеграциями рано или поздно придется столкнуться с получением JSON файлов. И, конечно же, жизнь заставит проверять файлы перед тем, как записывать данные в БД.

28.08.2023    8799    YA_418728146    6    

141

Внешние компоненты Native API на языке Rust - Просто!

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

Внешние компоненты для 1С можно разработывать очень просто, пользуясь всеми преимуществами языка Rust - от безопасности и кроссплатформенности до удобного менеджера библиотек.

20.08.2023    6271    sebekerga    54    

94

Все скопируем и вставим! (Буфер обмена в 1С 8.3.24)

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

Рассмотрим новую возможность 8.3.24 и как её можно эффективно использовать

27.06.2023    15962    SeiOkami    31    

103
Комментарии
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
1. mszsuz 322 31.03.15 11:01 Сейчас в теме
Рекурсия требует доп.расходов ресурсов и не удобна из-за того, что выходим из области видимости остальных переменных - приходится или параметрами их передавать или объявлять в теле модуля. Любую выборку можно обойти в одной процедуре и без рекурсий.
2. 32ops 191 31.03.15 11:10 Сейчас в теме
(1) Согласен. Но в данной статье не рассматривается преобразование рекурсии в циклический алгоритм, т.к. это отдельная тема. Хотя, в принципе, можно добавить нерекурсивный алгоритм в качестве примера.
8. 32ops 191 01.04.15 11:27 Сейчас в теме
(1) Вот пример без рекурсии
	ВыборкаНоменклатура = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией,"Номенклатура");
	
	Стек = Новый Массив ( 200 );
	КоличествоВСтеке=0;
	Выход=Не ВыборкаНоменклатура.Следующий();
	
	Пока Не Выход Цикл
		Пока ВыборкаНоменклатура.ТипЗаписи()=ТипЗаписиЗапроса.ИтогПоИерархии Цикл
			Стек[КоличествоВСтеке]=ВыборкаНоменклатура;
			КоличествоВСтеке=КоличествоВСтеке+1;
			// Обработка папки
			Сообщить(ВыборкаНоменклатура.Номенклатура);
			ВыборкаНоменклатура=ВыборкаНоменклатура.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией,"Номенклатура");
			ВыборкаНоменклатура.Следующий();
		КонецЦикла;
		// Обработка элемента
		Сообщить(ВыборкаНоменклатура.Номенклатура);
		// Обработка следующей группировки
		ВыбратьДанные(ВыборкаНоменклатура.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам));
		ЕстьСледующий= ВыборкаНоменклатура.Следующий();
		Пока Не ЕстьСледующий И КоличествоВСтеке>0 Цикл
			КоличествоВСтеке=КоличествоВСтеке-1;
			ВыборкаНоменклатура=Стек[КоличествоВСтеке];
			ЕстьСледующий= ВыборкаНоменклатура.Следующий();
		КонецЦикла;
		Если Не ЕстьСледующий И КоличествоВСтеке=0 Тогда
			Выход=Истина;
		КонецЕсли;
	КонецЦикла;
Показать
Alien_job; Shurik1C; +2 Ответить
14. Alien_job 190 07.04.16 09:54 Сейчас в теме
(8) Я правильно понял, что в примере без рекурсии "ВыбратьДанные" имеется ввиду обработать подчиненные группировки?
3. dick steel 31.03.15 11:28 Сейчас в теме
Гуд. Но почему нету примера, когда в методе "Выбрать" указывается 3 параметра?
Автор, допиши статью, указав пример с использованием 3-ех параметров (подсказка - хороший пример при работе с датами). Сделай из своей статьи конфетку ;-)
10. 32ops 191 01.04.15 13:54 Сейчас в теме
(3) Честно говоря не понял, как это к статье относится
4. TODD22 18 31.03.15 13:22 Сейчас в теме
При использовании Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией) обязательно указание второго параметра, строки с именем поля группировки.

Второй параметр вроде как не обязательный. И если у нас нет других полей группировки то можно и не указывать второй параметр.
9. 32ops 191 01.04.15 13:51 Сейчас в теме
12. Shurik1C 05.01.16 18:54 Сейчас в теме
(9)

Спасибо! Решил проблему:)
5. Yashazz 4709 31.03.15 14:45 Сейчас в теме
Всем советую ознакомиться с публикациями пользователя Ildarovich. Тогда вам откроется истина.
6. Shurik1C 31.03.15 16:35 Сейчас в теме
У меня сейчас есть подобная задача, построить отчет в виде пирамиды сверху вниз, и я вот никак не могу его побороть(((
Уже кажется что в 1С эта задача не реализуема(((
Прикрепленные файлы:
7. 32ops 191 31.03.15 17:15 Сейчас в теме
(6) Дак выгрузи в дерево, чем не пирамида))
11. Dnki 4 23.07.15 21:28 Сейчас в теме
Материал почитал с удовольствием. Часто простые вещи не пишутся простым языком.
Спасибо.
13. Alien_job 190 07.04.16 09:42 Сейчас в теме
Спасибо. Раньше не сталкивался с обходом по иерархии а камней подводных оказывается навалом!
15. 32ops 191 07.04.16 09:56 Сейчас в теме
16. kalyaka 1053 14.04.22 22:55 Сейчас в теме
При обходе выборки мы можем находиться в текущий момент на элементе или папке
Неоднозначная формулировка, ведь при группировке по иерархии подразумевается, что поле группировки иерархическое. В таком случае действительно будут и папки и элементы. Однако если справочник подчинен элементам? Тогда будут группировки по элементам.

Я бы здесь все-таки разделил. Папки - это те же элементы справочника, как и элементы, которым подчинены другие папки или элементы. А вот когда в запросе выбираются итоги по, то в результат запроса помимо самой выборки платформа добавляет еще группировки (строки итогов).

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

Если в итогах нет модификаторов, то это будут группировки по значению поля. Для иерархического справочника в такой группировке мало смысла, т.к. все элементы уникальны.

Если в итогах указать модификатор ИЕРАРХИЯ, то платформа помимо итоговых группировок для элементов еще добавит элементы иерархии и по ним также итоговые группировки. Получатся итоги по элементам и по группам элементов - избыточное количество итогов. При этом сами элементы иерархии будут входить в свою же группировку.

Если указать модификатор ТОЛЬКО ИЕРАРХИЯ, то платформа добавит итоговые группировки только по элементам иерархии. При этом сами элементы иерархии будут входить в свою же группировку.

И наконец самый практичный вариант: ТОЛЬКО ИЕРАРХИЯ и условие на элемент НЕ ЭтоГруппа. В таком варианте будут выведены элементы сгруппированные по папкам. Однако такой вариант не сработает, если есть иерархия элементов.

Когда происходит обход по иерархической группировке, то этот обход всегда происходит на одном уровне иерархии. Если нам встречается итоговая запись, не важно какой итог (по иерархии или по группе), то нужно выбрать следующий уровень иерархии группировки: для итога по иерархии - ОбходРузультатаЗапроса.ПоГруппировкамСИерархией, а для итога по группировке (всегда присутствует на последнем уровне группировки по выбранному полю) - ПоГруппировкам. При этом нужно обязательно указать имя поля группировки то же самое или просто передать в выборку значение функции Выборка.Группировка(). Это нужно сделать для того, чтобы платформа не выбрала сама следующую группировку итогов или детальные записи, т.к. в платформе такое поведение заложено по-умолчанию.
mevgenym; Sindbad_M; +2 Ответить
17. user1233082 20 11.01.24 16:04 Сейчас в теме
Оставьте свое сообщение