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

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 Конфигурации 1cv8 Бесплатно (free)

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

23.06.2024    7459    bayselonarrend    20    

154

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

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

13.03.2024    5947    dsdred    16    

80

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

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

24.01.2024    17674    YA_418728146    26    

71

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

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

11.12.2023    11227    dsdred    44    

130

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

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

06.10.2023    23763    SeiOkami    48    

135

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

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

14.09.2023    18835    human_new    27    

80

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

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

28.08.2023    14735    YA_418728146    7    

166
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. mszsuz 335 31.03.15 11:01 Сейчас в теме
Рекурсия требует доп.расходов ресурсов и не удобна из-за того, что выходим из области видимости остальных переменных - приходится или параметрами их передавать или объявлять в теле модуля. Любую выборку можно обойти в одной процедуре и без рекурсий.
2. 32ops 195 31.03.15 11:10 Сейчас в теме
(1) Согласен. Но в данной статье не рассматривается преобразование рекурсии в циклический алгоритм, т.к. это отдельная тема. Хотя, в принципе, можно добавить нерекурсивный алгоритм в качестве примера.
8. 32ops 195 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 195 01.04.15 13:54 Сейчас в теме
(3) Честно говоря не понял, как это к статье относится
4. TODD22 19 31.03.15 13:22 Сейчас в теме
При использовании Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией) обязательно указание второго параметра, строки с именем поля группировки.

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

Спасибо! Решил проблему:)
5. Yashazz 4790 31.03.15 14:45 Сейчас в теме
Всем советую ознакомиться с публикациями пользователя Ildarovich. Тогда вам откроется истина.
6. Shurik1C 31.03.15 16:35 Сейчас в теме
У меня сейчас есть подобная задача, построить отчет в виде пирамиды сверху вниз, и я вот никак не могу его побороть(((
Уже кажется что в 1С эта задача не реализуема(((
Прикрепленные файлы:
7. 32ops 195 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 195 07.04.16 09:56 Сейчас в теме
16. kalyaka 1105 14.04.22 22:55 Сейчас в теме
При обходе выборки мы можем находиться в текущий момент на элементе или папке
Неоднозначная формулировка, ведь при группировке по иерархии подразумевается, что поле группировки иерархическое. В таком случае действительно будут и папки и элементы. Однако если справочник подчинен элементам? Тогда будут группировки по элементам.

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

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

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

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

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

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

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