Применение рекурсивных функций при построении отчета с иерархией

Опубликовал Олег Пономаренко (O-Planet) в раздел Программирование - Практика программирования

Особенностью справочников в восьмерке является возможность их неограниченной иерархии. Тот, кто имел дело только с 7.7, столкнувшись с теоретической возможностью сколь угодного числа вложений, может стать в тупик: как организовать обход группировок, когда заранее не известно их число...
Сформулируем задачу: имеются некие данные, сгруппированные по значению справочника, например, регистр «ПартииТоваровНаСкладах» с измерением типа «Номенклатура». Нам необходимо вывести отчет с отражением иерархической структуры этого справочника, т.е., в нашем примере, сгруппировать остатки по группам и подгруппам товаров.

Особенностью справочников в восьмерке является возможность их неограниченной иерархии. Тот, кто имел дело только с 7.7, столкнувшись с теоретической возможностью сколь угодного числа вложений, может стать в тупик: как организовать обход группировок, когда заранее не известно их число?

Не буду рассматривать вариант с построителем отчета: делаем все вручную.

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

Строим процедуру на кнопке "Сформировать":

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


Итак, у нас имеется таблица остатков товаров. Добавим в нее и заполним свою колонку «Уровень»

Товары
.
Колонки
.
Добавить
("Уровень")
;
Для
Каждого Стр Из Товары 
Цикл
Стр
.
Уровень
=
Стр
.
Номенклатура
.
Уровень;
КонецЦикла
;


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

Группы
=
Товары
.
СкопироватьКолонки
()
;
Для
Каждого Стр Из Товары 
Цикл
Родитель
=
Стр
.
Номенклатура
.
Родитель;
  
Пока
Родитель
<>
Справочники
.
Номенклатура
.
ПустаяСсылка
() Цикл
Нов
=
Группы
.
Добавить
()
;
    Нов
.
Номенклатура
=
Родитель;
    Нов
.
Родитель
=
Родитель
.
Родитель;
    Нов
.
Уровень
=
Родитель
.
Уровень
()
;
    Нов
.
КоличествоОстаток
=
Стр
.
КоличествоОстаток;
    Родитель
=
Родитель
.
Родитель;
  
КонецЦикла
;
КонецЦикла
;


(Понимаем, что этот модуль можно было объединить с предыдущим, но для наглядности разделяем)

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

Группы
.
Свернуть
("Номенклатура,Родитель,Уровень","КоличествоОстаток")
;


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

Макет
=
ПолучитьМакет
("Макет")
;
Область
=
Макет
.
ПолучитьОбласть
("Шапка")
;
ЭлементыФормы
.Таблица.
Вывести
(
Область
)
;

Родитель
=
Справочники
.
Номенклатура
.
ПустаяСсылка
()
;
ВывестиНоменклатуру
(
Макет
,0,
Родитель 
,
Группы
,
Товары
)
;

Область
=
Макет
.
ПолучитьОбласть
("Подвал")
;
ЭлементыФормы
.Таблица.
Вывести
(
Область
)
;

КонецПроцедуры

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

Процедура
ВывестиНоменклатуру 
(
Макет
,
Уровень
,
Родитель
,
Группы
,
Товары
) // выводит товары для группы Родитель на текущем уровне Для
Каждого Стр Из Рез 
Цикл Если (
Стр
.
Уровень
=
Уровень
)
и
(
Стр
.
Родитель
=
Родитель
) Тогда
ВывестиСтрокуТовара
(
Макет
,
Стр
)
;
    
КонецЕсли
;
  
КонецЦикла // выводит рекурсивно подгруппы товаров для группы Родитель на текущем уровне Для
Каждого Стр Из Группы 
Цикл Если (
Стр
.
Уровень
=
Уровень
)
и
(
Стр
.
Родитель
=
Родитель
) Тогда
ВывестиСтрокуГруппы
(
Макет
,
Стр
)
;
      ВывестиНоменклатуру 
(
Макет
,
Уровень
,
Родитель
,
Группы
,
Товары
)
;
    
КонецЕсли
;
  
КонецЦикла
;
КонецПроцедуры

Стоит доопределить элементарные функции вывода строк таблицы на печать "ВывестиСтрокуТовара" и "ВывестиСтрокуГруппы", и задача решена полностью.

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

См. также

Комментарии
1. Сергей Старовойтов (AVARY) 173 06.09.08 11:06 Сейчас в теме
Выполнив следующий запрос:
Код
   Запрос = Новый Запрос;
   Запрос.Текст =
   "ВЫБРАТЬ
   |   ПартииТоваровНаСкладахОстатки.Номенклатура,
   |   ПартииТоваровНаСкладахОстатки.Номенклатура.Родитель КАК НоменклатураРодитель,
   |   ПартииТоваровНаСкладахОстатки.КоличествоОстаток КАК КоличествоОстаток
   |ИЗ
   |   РегистрНакопления.ПартииТоваровНаСкладах.Остатки КАК ПартииТоваровНаСкладахОстатки
   |
   |УПОРЯДОЧИТЬ ПО
   |   НоменклатураРодитель УБЫВ
   |ИТОГИ ПО
   |   НоменклатураРодитель ИЕРАРХИЯ";
   
   Дерево = Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией);
Показать полностью

можно сразу получить дерево, после чего организовать его рекурсивный вывод. Для определения цвета строки также используем метод
Код
Уровень()
Показать полностью
, ну и не забываем про то что в 8.х есть возможность группировки строк в таблицах. :)
З.Ы.: Для того, чтобы понять рекурсию, нужно понять рекурсию :)
lomok; coder1cv8; Abadonna; +3 Ответить 3
2. Андрей Скляров (coder1cv8) 3282 06.09.08 16:28 Сейчас в теме
Нда... Вот поэтому и говорят, что выучить восьмерку проще людям не отягащенным общением с 7.7...
Ну ничего, семерошники бывает ещё и не такое отжигают! )))
3. Аркадий Кучер (Abadonna) 3661 06.09.08 17:02 Сейчас в теме
>Вот поэтому и говорят, что выучить восьмерку проще людям не отягащенным общением с 7.7...
Выучить восьмерку проще людям не отягащенным общением с 1С ВАЩЕ ;) А работающим на приличных языках типа Си, Дельфи и даже Basic на худой конец
4. Аркадий Кучер (Abadonna) 3661 06.09.08 17:11 Сейчас в теме
Эх, блин ;) Хотел Планет крутизну публикнуть, ан не вышло :)
5. Аркадий Кучер (Abadonna) 3661 06.09.08 17:15 Сейчас в теме
Гы, да еще и мой земляк по носу щелкнул. Жму лапу :)))) Krasnoyasrsk - rules
6. Сергей Старовойтов (AVARY) 173 06.09.08 18:54 Сейчас в теме
Ну, вообще-то во всей этой истории к 8.х имеет отношение только фраза о неограниченном количестве уровней иерархии. В 7.7 задачу можно решить аналогичным образом, сформировав прямой запрос, с последующей выгрузкой в индексированную таблицу.
Мне искренне жаль тех людей, которые пишут на чистом 1с 7.7.
7. Олег Пономаренко (O-Planet) 6661 06.09.08 23:10 Сейчас в теме
(1-6)
Вы вообще, о чем? Жесть! Обсуждают пример. Мне что, надо было приводить супер навороченный запрос, чтобы ни кто не разобрался, что там и к чему? Я взял элементарнейший пример, который будет всем понятен. Для дураков написал приписку "Возможно, задачу можно решить проще, организовав мудрый запрос ... " Кто-нить вообще доклады делал когда-нибудь? Обратите внимание, что обычно вся теория комментируется примерами в 2-х, максимум, в 3-х мерных пространствах. Суть статьи - показать, как, имея таблицу данных, получить таблицу иерархии и обойти ее рекурсивно. На практике, не всегда имеется возможность сразу получать таблицу с иерархией. Иногда результирующая таблица собирается из нескольких. Пример, приведенный в (1), убивает часть статьи и лишает ее наглядности.

(6) Тогда уж искренне пожалей тех, кто кодируют на ассемблере. Мне искренне жаль людей, кто начинает изучать программирование с Дельфи и, что хуже, с 1С в любой интерпретации, не почуствовав все нюансы работы с невизуальными средами.
8. Олег Пономаренко (O-Planet) 6661 07.09.08 00:36 Сейчас в теме
Плюс ко всему, запрос в (1) не рабочий. Дерево-то он формирует, но количество в узлах не считает.

Код
Процедура Вывести(Строки,Ур)
   Ном=0;
   Для Каждого Стр Из Строки Цикл
      Ном=Ном+1;
      Если Стр.Строки.Количество()=0 Тогда
         Сообщить(?(Ур="","",Ур+".")+Строка(Ном)+": "+Строка(Стр.Номенклатура)+": "+Строка(Стр.КоличествоОстаток));
      Иначе   
         Сообщить(?(Ур="","",Ур+".")+Строка(Ном)+": "+Строка(Стр.НоменклатураРодитель)+": "+Строка(Стр.КоличествоОстаток));
         Вывести(Стр.Строки,?(Ур="","",Ур+".")+Строка(Ном));
      КонецЕсли;   
   КонецЦикла;   
КонецПроцедуры   

Процедура КнопкаВыполнитьНажатие(Кнопка)
   Запрос = Новый Запрос;
   Запрос.Текст =
   "ВЫБРАТЬ
   |   ПартииТоваровНаСкладахОстатки.Номенклатура,
   |   ПартииТоваровНаСкладахОстатки.Номенклатура.Родитель КАК НоменклатураРодитель,
   |   ЕстьNULL(ПартииТоваровНаСкладахОстатки.КоличествоОстаток,0) КАК КоличествоОстаток
   |ИЗ
   |   РегистрНакопления.ПартииТоваровНаСкладах.Остатки КАК ПартииТоваровНаСкладахОстатки
   |
   |УПОРЯДОЧИТЬ ПО
   |   НоменклатураРодитель УБЫВ
   |ИТОГИ ПО
   |   НоменклатураРодитель ИЕРАРХИЯ";
   
   Дерево = Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией);
   
   Вывести(Дерево.Строки,"");
КонецПроцедуры
Показать полностью


Результат:

1: Инвентарь:
1.1: Грабли: 40
1.2: Мотоблок: 9
1.3: Лопата: 34
1.4: Метла: 24
1.5: Вилы: 20
2: Тара:
2.1: Ящик (упаковка для вентиляторов): 28
2.2: Ящик - упаковка для телевизора: 2
3: Сборка компьютеров:
3.1: Комплектующие:
3.1.1: Монитор: 55
3.1.2: Системный блок: 55
3.1.3: Мышь: 55
3.1.4: Клавиатура: 35
...

Колдовать с "Итог"?

Если предлагается альтернативный пример, то все-таки, желательно, чтобы он работал...
9. Сhe Burashka (CheBurator) 07.09.08 02:16 Сейчас в теме
мдя.. печально... как-то от 8-ки ожидается что-то более интересное, чем тупое повторение того, что на 7-ке сделано давным-давно...
+ стандарт скуля позволяет организовать рекурсию прям в запросе...
10. Сергей Старовойтов (AVARY) 173 07.09.08 07:48 Сейчас в теме
Эх, как не хотелось, но все же поставил 8.1 на домашнем ноуте...
(7) О неработоспособности запроса можно говорить только тогда, когда при его выполнении система выдает ошибку, во всех остальных случаях уместнее сказать что запрос работает не так как требовалось.
Если уж говорить о получении данных в требуемом формате полностью из результата запроса, то чуть подкорректируем его:
Код
   "ВЫБРАТЬ
   |   ПартииТоваровНаСкладахОстатки.Номенклатура,
   |   ПартииТоваровНаСкладахОстатки.Номенклатура.Родитель КАК НоменклатураРодитель,
   |   ПартииТоваровНаСкладахОстатки.КоличествоОстаток КАК КоличествоОстаток
   |ИЗ
   |   РегистрНакопления.ПартииТоваровНаСкладах.Остатки КАК ПартииТоваровНаСкладахОстатки
   |
   |УПОРЯДОЧИТЬ ПО
   |   НоменклатураРодитель УБЫВ
   |ИТОГИ
   |   СУММА(КоличествоОстаток)
   |ПО
   |   НоменклатураРодитель ИЕРАРХИЯ";
Показать полностью

Данное обсуждение не состоялось бы, если текст статьи соответствовал заголовку. Заходя по ссылке сюда надеялся встретить какой-нибудь изящный, хитрый рекурентный алгоритм. И что я вижу: бравым тоном разъясняется героическое решение проблем, которые программист может создать сам себе.
З.Ы.: Не считаю запрос навороченным, если в нем нет ни одного соединения. Будь там выборка хоть ста полей.
lomok; Abadonna; ILM; +3 Ответить 2
11. Аркадий Кучер (Abadonna) 3661 07.09.08 08:20 Сейчас в теме
Молодец! Сперва по носу щелкнул, теперь по лбу ;)

12. Сергей Старовойтов (AVARY) 173 07.09.08 10:00 Сейчас в теме
:) Если бы это был мой блог, то я бы переместил бы его из раздела "Полезные технологии" не в "Грусть", а в "Юмор".

Для окрыленных рейтингом поясню суть "колдовства" с "Итог":
1. Считается, что у вас открыт конфигуратор 1с 8.1 и перед Вами запрос из (1);
2. Помещаете каретку возле любого из символов текста запроса (это несложно);
3. Нажимаете кнопку для вызова контекстного меню (находится слева от правой клавиши "Ctrl");
4. Нажимаете кнопку "Вниз" 11 (одиннадцать) раз до выделения строки меню "Конструктор запроса";
5. Нажимаее клавишу "Enter". При правильном выполнении первых пунктов, перед Вами должен открыться "Конструктор запроса", если этого не произошло, повторите все сначала;
6. Нажимаем клавишу "Enter" 6 (шесть) раз, для перехода на вкладку "Итоги";
7. Нажимаем клавишу "Tab" 4 (четыре) раза, для активизации строки "Номенклатура" в дереве "Поля";
8. Нажимаем клавишу "Вниз" 1 (один) раз, для активизации строки "КоличествоОстаток" в дереве "Поля";
9. Нажимаем клавишу "Tab" 5 (пять) раз, для активизации кнопки ">", находящейся слева от таблицы итоговых полей;
10. Нажимаем клавишу "Enter" 1 (один) раз, для переноса поля "КоличествоОстаток" в таблицу итоговых полей;
11. Удерживая клавишу "Ctrl", нажимаем клавишу "Enter", для формирования текста запроса.

Если Вы сделали все правильно, то перед Вами появится текст запроса из (10) и "колдовство" можно счиать состоявшимся. Если Вы получили другой результат, то, к сожалению, необходимо повторить все сначала.
13. Аркадий Кучер (Abadonna) 3661 07.09.08 10:08 Сейчас в теме
(12) Просто мне уже грустно Планету объяснять кое-что... вот я и переместил в "Грусть"
14. Андрей Скляров (coder1cv8) 3282 07.09.08 11:56 Сейчас в теме
(7) Не знаю, кто о чем... А я о том, что статья это пример того как делать НЕ надо.
И я могу ещё пяток примеров привести решения подобной задачи через ж... Но если ты пишешь статью, то я думаю, нужно стараться показать оптимальное решение. Всё решается очень простым запросом с итогами. Всё! Какие навороты?! Ведь это будут читать люди, которые только начинают изучать восьмерку, а то что написано в статье - методически не грамотно.
Но есть такие люди которые никогда не скажут: "да, ерунду написал", правда?... )
A.Belash; lomok; Abadonna; +3 Ответить 1
15. Аркадий Кучер (Abadonna) 3661 07.09.08 12:07 Сейчас в теме
(14) Тут все очень просто. Человек, едва начав изчать 8-ку создал себе идиотскую проблему, кою и решил идиотским способом. Но поскольку, как говорит vip "шпингале... и памфары", срочно захотелось блеснуть мощью интеллекта. Ну ладно бы в 7-ке, где он нормальный девелопер, но тут то куда с голой пяткой против шашки?
16. Андрей Скляров (coder1cv8) 3282 07.09.08 12:22 Сейчас в теме
(15) Согласен. В общем-то ничего страшного тут нет, как я уже говорил, после клюшек, человек не разобравшись может ещё и не такое написать... )
Примечательно, что Planet никогда не скажет, что ерунду сморозил... )

17. Аркадий Кучер (Abadonna) 3661 07.09.08 12:25 Сейчас в теме
Кстати, Планет, обрати внимание, какие тут корректные люди собрались!
Мордой в парашу тебя ткнули, но МИНУС никто не поставил ;)
18. Сергей Старовойтов (AVARY) 173 07.09.08 12:34 Сейчас в теме
Для перевода блога обратно в "Полезные технологии" привожу рекурентный алгоритм формирования дерева из таблицы значений. Итак, если все же к Вам пришла Таблица:
Код
////////////////////////////////////////////////////////////////////////////////
// ПоместитьЭлементВДерево(Элемент, Количество, ДеревоЭлементов)
//
// Параметры:
//   Элемент      - СправочникСсылка. Элемент справочника, который необходимо 
//              поместить в дерево "ДеревоЭлементов";
//   Количество      - Число. Количество элемента или итог количества элементов по 
//              группе;
//   ДеревоЭлементов   - ДеревоЗначений. Дерево значений, в которое необходимо 
//              поместить элемент справочника "Элемент". Структура
//              дерева:
//              1. Элемент   - СправочникСсылка;
//              2. Количество   - Число.
//
// Описание:
//   Процедура добавляет элемент справочника "Элемент" и его количество "Количество" в дерево 
//   "ДеревоЭлементов". Элементы   добавляются в дерево с учетом иерархии элементов в справочнике.
//   По группам элементов, формируются итоги по количеству.
Процедура ПоместитьЭлементВДерево(Элемент, Количество, ДеревоЭлементов)

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

   ДеревоЭлементовСтрокаЭлемента.Количество = ТекущееКоличество + Количество;
   
КонецПроцедуры // ПоместитьЭлементВДерево(Элемент, Количество, ДеревоЭлементов)

////////////////////////////////////////////////////////////////////////////////
// СформироватьДерево(ТаблицаЭлементов)
//
// Параметры:
//   ТаблицаЭлементов   - ТаблицаЗначений. Таблица, которую необходимо преобразовать 
//                    в дерево значений. Структура таблицы:
//                    1. Элемент   - СправочникСсылка;
//                    2. Количество   - Число.
//
// Описание:
//   Функция предназначена для преобразования таблицы "ТаблицаЭлементов" в дерево
//   значений. Иерархия элементов в дереве соответствует иерархии элементов в справочнике.
//
// Возвращаемое значение:
//   ДеревоЗначений   - дерево иерархии элементов таблицы "ТаблицаЭлементов". Структура
//                 лерева:
//                 1. Элемент   - СправочникСсылка;
//                 2. Количество   - Число.
Функция СформироватьДерево(ТаблицаЭлементов)
   
   ДеревоЭлементов = Новый ДеревоЗначений; 
   ДеревоЭлементов.Колонки.Добавить("Элемент");
   ДеревоЭлементов.Колонки.Добавить("Количество");
   
   Для Каждого ТаблицаЭлементовСтрока Из ТаблицаЭлементов Цикл
      
      Элемент      = ТаблицаЭлементовСтрока.Элемент;
      Количество   = ТаблицаЭлементовСтрока.Количество;
      ПоместитьЭлементВДерево(Элемент, Количество, ДеревоЭлементов);
      
   КонецЦикла; // Конец цикла по элементам таблицы элементов
   
   Возврат ДеревоЭлементов;
   
 КонецФункции // СформироватьДерево(ТаблицаЭлементов)

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|   ПартииТоваровНаСкладахОстатки.Номенклатура       КАК Элемент,
|   ПартииТоваровНаСкладахОстатки.КоличествоОстаток КАК Количество
|ИЗ
|   РегистрНакопления.ПартииТоваровНаСкладах.Остатки КАК ПартииТоваровНаСкладахОстатки";

Дерево = СформироватьДерево(Запрос.Выполнить().Выгрузить());
Показать полностью

З.Ы.: В реальной задаче я бы запульнул табличку во внутреннюю таблицу и выполнил запрос, аналогичный (10). Приведенный рекурентный алгоритм работает в 500 раз дольше, чем выполняется запрос в (10).
19. Аркадий Кучер (Abadonna) 3661 07.09.08 12:36 Сейчас в теме
(18) Сергей, ты уж лучше сам напиши блог а "Полезные технологии".
Тут ведь грусть не о коде, а кое о чем другом....
20. Олег Пономаренко (O-Planet) 6661 08.09.08 01:50 Сейчас в теме
За (18) - плюс однозначно. Я восьмерку действительно, недавно изучаю, с деревьями не работал. Вернее, поработал вчера впервые ;) Взял на вооружение. Действительно, все очень оптимально выглядит, намного лучше, чем с таблицами. В (12) повеселил. Сделай, друг, милость, распиши также подробно для окрыленных рейтингом, как с помощью конструктора строить вложенные запросы типа:

ВЫБРАТЬ
НЕЧТО.ПОЛЕ1,
...
ИЗ (ВЫБРАТЬ ... ) КАК НЕЧТО

честно, не вьеду, леплю вручную :)

Собственно, вы все мне тут про запрос толкуете, но я-то более хотел про рекурсию поговорить, точнее, про функцию "ВывестиНоменклатуру", а запрос взял чисто для того, чтобы получить заполненную таблицу. Запрос взял элементарнейший. У меня запрос объединяет данные по нескольким регистрам, поэтому там предложенный алгоритм с иерархией не пройдет: просто иерархия предполагает один справочник, у меня их может быть несколько разных. Правильнее было бы озаглавить именно так: "Итак, если все же к Вам пришла Таблица..."

Абадонна, ты-то что прыгаешь? Я вполне нормально отношусь к критике, если она по существу. Блог удалять не буду, потому что в комментариях есть много полезного. Кстати, если когда-либо встретимся, то могу продемонстрировать наглядно, что можно сделать пяткой против шашки ;)
21. Сhe Burashka (CheBurator) 08.09.08 02:11 Сейчас в теме
еще раз: ничего нового про рекурсию рассказано не было.. совершенно аналогичное в типовых ТиСах 7-ки уже сто лет в обед...
..
по пятки и шашки - не надо.. не надо... махатья пятками профессионально против шашек для 1Сника - очень вредно... ;-)
22. Аркадий Кучер (Abadonna) 3661 08.09.08 02:20 Сейчас в теме
(21) вот именно! да и что нового про нее сказать можно ;)
(20)>то могу продемонстрировать наглядно, что можно сделать пяткой против шашки ;)
А заодно попозже написать блог "В отделении нейрохирургии очень хорошие врачи" :)
23. Олег Пономаренко (O-Planet) 6661 08.09.08 02:41 Сейчас в теме
Рыбят! Проще надо быть. Это вы все наровите выложить нечто эпохальное. Обсуждается всего лишь рекурсия в применении к построению отчета. Вам это известно - мАлАдцы! Я лично не так часто встречал рекурсивные функции в 1С. Подумал, что кому-то пригодится, вот и выложил.

Про шашки и пятки - вам сюда: http://russianspetsnaz.com/vidio-clip.php , что бы немного развеялись стереотипы...
24. Аркадий Кучер (Abadonna) 3661 08.09.08 03:05 Сейчас в теме
(23) Назвал бы блог "Некоторые возможности применения рекурсивных функций в среде 1С", может ни у кого бы вопросов и не возникло....
25. Олег Пономаренко (O-Planet) 6661 08.09.08 03:15 Сейчас в теме
Да наверное, так и надо было. Писалось с 7 до 8 утра с пятницы на субботу, после 2 л. сбитня и 7 часов игры в Two Worlds... А такой блог точно надо сделать. Сталкивался много раз с тем, что народ не понимает рекурсию и боится ее использовать.
26. Олег Пономаренко (O-Planet) 6661 08.09.08 03:17 Сейчас в теме
27. Сергей Старовойтов (AVARY) 173 08.09.08 07:36 Сейчас в теме
По просьбе в (20): вот так вот раз доступно объеснишь и тебе уже на шею садятся...
1. Выполняем шаги 3-5 из (12);
2. Нажимаешь клавишу "Tab" 9 раз, для активизации строки в дереве "Таблицы";
3. Нажимаешь клавишу "ins" 1 раз, для перехода в конструктор вложенного запроса.
28. Олег Пономаренко (O-Planet) 6661 08.09.08 08:03 Сейчас в теме
Ладно, клавиши, допустим, я нажимать научился. Точнее, там ведь вроде звездочка есть, которая создает вложенный запрос... А вот с чем бы действительно, помог, так это с одной проблемкой... Есть у меня таблица значений, заполненная не важно чем. Хотю ее в запрос включить. Это вообще возможно?

ВЫБРАТЬ

Док.нечто

ИЗ

Документы.Какието как Док

ВНУТРЕННЕЕ СОЕДИНЕНИЕ

<МояТаблица>

ПО

Документы.Какието.Реквизит = <МояТаблица>.Колонка
29. Сергей Старовойтов (AVARY) 173 08.09.08 08:11 Сейчас в теме
Можно. Для этого используются внутренние таблицы.
30. Андрей Скляров (coder1cv8) 3282 08.09.08 08:12 Сейчас в теме
(28) Ну это уж совсем элементарно... )
Код
Запрос=Новый Запрос;
Запрос.МенеджерВременныхТаблиц=Новый МенеджерВременныхТаблиц;
Запрос.Текст="ВЫБРАТЬ * ПОМЕСТИТЬ МояТаблица ИЗ &ТЗ КАК ТЗ";
Запрос.УстановитьПараметр("ТЗ",ТЗ);
Запрос.Выполнить();
Показать полностью

Ну и дальше пишешь, собственно, свой запрос так же как выше написал...
ЗЫ: Не забываем, таблица значений должна быть типизированна.
31. Lomok (lomok) 08.09.08 08:20 Сейчас в теме
Я опять все проспал, но автор однозначно жжот :)
32. Аркадий Кучер (Abadonna) 3661 08.09.08 08:22 Сейчас в теме
(27)-(31) Забавно!
Из блога "ляля-крутизна" превращаемся в вопрос на форуме "поможите, люди добрые" :)))))
33. Lomok (lomok) 08.09.08 08:26 Сейчас в теме
(32) Да ладно, O-Planet в отличии, например, от меня, хотя бы что-то пишет, выкладывает...Пусть не всегда удачно получается :)
34. Олег Пономаренко (O-Planet) 6661 08.09.08 08:37 Сейчас в теме
(30) Мож и элементарно, но ни тут на форуме, ни на мисте не ответили. правда, тогда задача несколько иначе формулировалась...
(32) Крутизна у тебя в голове. Где в этом блоге, скажи, я хоть намек на крутизну давал? Просто секрет тебе маленький открою: люди судят обо всем в меру собственной испорченности ;) Вообще-то, это совсем не я недавно рубаху рвал на площади, что разные колодезные люки выглядят круче моих суперуникальнонавороченных разработок. Этот блок - рабочая записка. Понравилась мне рекурсия, решил поделиться. Попутно пару вопросов решил, что-то новое узнал. Хороший блог.
35. Аркадий Кучер (Abadonna) 3661 08.09.08 08:41 Сейчас в теме
(34) Ну, во-первых, я ничего не рвал, а, во-вторых, тебе ж ясно написали, чем и когда я могу гордиться. В моей-то голове точно крутизна, а вот........
36. Олег Пономаренко (O-Planet) 6661 08.09.08 08:41 Сейчас в теме
Кстати, нашел тот вопрос:

Есть некоторые документы, имеющие два реквизита типа Дата - период актуальности. Нужно сделать, чтобы один и тот же документ присутствовал N раз в результирующей таблице, в зависимости от своего периода актуальности.

01.01.01 Документ 1 (с 01.01.01 по 05.01.01)
02.01.01 Документ 1 (с 01.01.01 по 05.01.01)
03.01.01 Документ 1 (с 01.01.01 по 05.01.01)
03.01.01 Документ 2 (с 03.01.01 по 05.01.01)
04.01.01 Документ 1 (с 01.01.01 по 05.01.01)
04.01.01 Документ 2 (с 03.01.01 по 05.01.01)
05.01.01 Документ 1 (с 01.01.01 по 05.01.01)
05.01.01 Документ 2 (с 03.01.01 по 05.01.01)

Помогут временные таблицы?
37. kitt al;dskjf;ldasjkf (kitt) 319 08.09.08 18:07 Сейчас в теме
Эх, где же это время, когда мне было интересно читать про 1с))? .NET Framework, вот где можно разгуляться.
38. Сhe Burashka (CheBurator) 08.09.08 19:47 Сейчас в теме
(37) дафай, дафай, гомельдрефф... ;-)
39. Олег Пономаренко (O-Planet) 6661 08.09.08 20:39 Сейчас в теме
Угу. А на 36 опять ответов нет. По ходу, такое нельзя сделать...
40. Lomok (lomok) 09.09.08 07:56 Сейчас в теме
(39)Сделать то можно, но временные таблицы там непричем.
41. Lomok (lomok) 09.09.08 07:57 Сейчас в теме
+(40)Руками придется ТЗ заполнять.
42. Сергей Старовойтов (AVARY) 173 10.09.08 06:25 Сейчас в теме
Если кому интересно, предлагаю следующую задачу: имеется дерево, в котором определено два поля, скажем "Ссылка" и "Пометка". Тип поля "Ссылка" - СправочникСсылка, тип поля "Пометка" - Булево. Листья дерева (элементы справочников) могут иметь пометку "Истина" или "Ложь", узлы дерева (группы справочников) пометки не имеют. Задача - получить дерево, содержащее только отмеченные или только неотмеченные листья дерева, в новое дерево лист должен переноситься со всеми родительскими узлами, с сохранением иерархии. Узел не имеющий помеченных (непомеченных) листьев, а также не имющий дочерних узлов с помеченными (непомеченными) листьями не переносится в итоговое дерево.
43. Олег Пономаренко (O-Planet) 6661 10.09.08 06:53 Сейчас в теме
Хм... Это проверка ума или правда нужно сделать? По ходу, не сложно.
44. Сергей Старовойтов (AVARY) 173 10.09.08 06:57 Сейчас в теме
Это проверка. По содержанию статьи я сразу понял, что для тебя это не сложно! Хочется сравнить алгоритмы различных авторов - ведь не исключен и вариант решения через таблицы значений ;)
45. Олег Пономаренко (O-Planet) 6661 10.09.08 07:58 Сейчас в теме
Я б рекурсией сделал. Собственно, делал такое, но на Builder c...
46. roma n (roma n) 6 10.09.08 11:11 Сейчас в теме
НайтиСтроки()+ a)Рекурсивно откапываем родителей (универсальное)
б) выполнить запрос к справочнику с итогами по иерархии (в контексте конкретной задачи)
(36) Все даты периода во временную таблицу и соединение к ней по Дата>=Документ.ДатаНачалаПериода И Дата <=Документ.ДатаОкончания. Не оно?
47. Max Potapov (Max.Potapov) 17.02.17 17:44 Сейчас в теме
Есть более интересное и простое решение на СКД - http://start1c.blogspot.ru/2017/01/blog-post.html