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

31.03.15

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

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

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

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

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

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

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

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

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

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

           

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

 

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

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

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

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



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

См. также

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

Про ООП в 1С и о том, как сделать свой код более кратким и выразительным при помощи использования текучего интерфейса (fluent interface).

03.02.2025    5835    bayselonarrend    126    

59

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

В платформе 8.3.27 появилась возможность использовать WebSocket-клиент. Давайте посмотрим, как это все устроено и чем оно нам полезно.

14.01.2025    7574    dsdred    57    

98

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

Эта небольшая статья - некоторого рода шпаргалка по файловым потокам: как и зачем с ними работать, какие преимущества это дает.

23.06.2024    11307    bayselonarrend    21    

162

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

Пример использования «Сервисов интеграции» без подключения к Шине и без обменов.

13.03.2024    7768    dsdred    18    

82

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

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

24.01.2024    26610    YA_418728146    33    

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

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

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

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

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

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

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

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

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

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