Переключение на Главную Страницу Страницы: 1 ОтправитьПечать
Горячая тема (более 10 ответов) Вывод справочника в соответствии с иерархией групп (число прочтений - 5052 )
DartVader
Junior Member
**
Отсутствует


1C++ rocks!

Сообщений: 29
Зарегистрирован: 13. Марта 2015
Вывод справочника в соответствии с иерархией групп
15. Мая 2017 :: 19:06
Печать  
Приветствую! Думаю все задавались вопросом как вывести в отчет элементы в соответствии с иерархией справочника, я этим вопросом мучился давно и вот разродился! смотрим, критикуем, копируем!

Функция ИнитТбУзла()   
     тбУзла = СоздатьОбъект("ТаблицаЗначений");   
     тбУзла.НоваяКолонка("родитель", "справочник.Товар");
     тбУзла.НоваяКолонка("Группа","справочник.Товар");
     тбУзла.НоваяКолонка("Уровень", "Число");
     тбУзла.НоваяКолонка("тбДети"); 
     Возврат тбУзла;
КонецФункции      


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


//*******************************************
Процедура Сформировать()                              
     
     RecordSet = СоздатьОбъект("ODBCRecordset");      
     текстСКЛ =  "
     |WITH Parts(ParentID, ID, goodsLevel) as
     |( 
     |    SELECT mainGoods.ParentID, mainGoods.ID, 0 goodsLevel
     |    FROM SC14 mainGoods
     |    WHERE mainGoods.ISFolder = 1 AND mainGoods.ParentID = $ПустойИД
     |    UNION ALL 
     |    SELECT childGoods.ParentID, childGoods.ID, goodsLevel + 1
     |    FROM SC14 childGoods
     |        INNER JOIN Parts p 
     |        ON childGoods.ParentID = p.ID AND childGoods.ISFolder = 1
     | ) 
     |SELECT ParentID [родитель $справочник.Товар], ID [Группа $справочник.Товар], goodsLevel Уровень
     |FROM Parts
     |ORDER BY goodsLevel DESC";
     
     
     тбРодителиИДети= RecordSet.ВыполнитьИнструкцию(текстСКЛ);
     тбРодителиИДети.НоваяКолонка("тбДети");
                  
     тбРодителиИДети.ПолучитьСтрокуПоНомеру(1);
     МаксУровень  =  тбРодителиИДети.Уровень;
     
     тбУзлаПустая = ИнитТбУзла();
     
     
     тбБуферВходящий = СоздатьОбъект("ТаблицаЗначений");
     тбУзлаПустая.Выгрузить(тбБуферВходящий);
     
     тбБуферИсходящий = СоздатьОбъект("ТаблицаЗначений");   
     тбУзлаПустая.Выгрузить(тбБуферИсходящий);
           
     текСтрока = 1;
     сч = МаксУровень;
     Пока сч > -1 Цикл                                                             
                       
           ОбрТекУровень(сч, тбРодителиИДети, тбБуферВходящий, тбБуферИсходящий, текСтрока, тбУзлаПустая);   
           тбБуферВходящий = тбБуферИсходящий;
           сч = сч - 1;
           
     КонецЦикла;
     
     тбПечать = СоздатьОбъект("ТаблицаЗначений");
     тбПечать.НоваяКолонка("Группа");
                 
     тбБуферИсходящий.Сортировать("Группа");
     
     ПечатьГрупп(тбБуферИсходящий,тбПечать);   
     
     //тбПечать.ВыбратьСтроку();
     
     
     
КонецПроцедуры
  
Наверх
 
IP записан
 
Djelf
God Member
*****
Отсутствует


Ubuntu + wine@etersoft
+ 1C 7.7

Сообщений: 634
Местоположение: Питер
Зарегистрирован: 02. Ноября 2007
Пол: Мужской
Re: Вывод справочника в соответствии с иерархией групп
Ответ #1 - 15. Мая 2017 :: 19:28
Печать  
Зачем cte если есть ИндексированнаяТаблица? Она сама сгруппирует по группам, а сортировка простейшей рекурсией по тзПотомки.

Ну а если cte то вот запрос для 1sqlite.
Все отсортировано уже в запросе и готово для отображение в виде дерева в ТабличномПоле.

Код (SQL)
Выбрать все
	WITH cte(id,parentid,level,isfolder,isviewed,ord)
	AS (
		SELECT
			s1.ID, s1.PARENTID, 1, s1.ISFOLDER,1, s1.ISFOLDER||s1.DESCR as ord
		FROM Справочник_Номенклатура AS s1
		WHERE s1.PARENTID =  '     0   '

		UNION ALL
		SELECT
			s2.ID, s2.PARENTID, cte.LEVEL+1, s2.ISFOLDER, 0, cte.ord||s2.ISFOLDER||s2.DESCR as ord
		FROM Справочник_Номенклатура AS s2
	    INNER JOIN cte ON cte.ID=s2.PARENTID
		WHERE cte.ISFOLDER=1

		ORDER BY ord
	)
--	INSERT INTO tree(parentid,id,level,isfolder,isviewed)
	SELECT
		cte.parentid [Родитель $Справочник.Номенклатура],
		cte.id  [Номенклатура $Справочник.Номенклатура],
		cte.level,
		cte.isfolder,
		cte.isviewed
	FROM cte
 

  
Наверх
www  
IP записан
 
DartVader
Junior Member
**
Отсутствует


1C++ rocks!

Сообщений: 29
Зарегистрирован: 13. Марта 2015
Re: Вывод справочника в соответствии с иерархией групп
Ответ #2 - 15. Мая 2017 :: 19:40
Печать  
Хехе так рекурсию использую просто не выложил тут Улыбка
  
Наверх
 
IP записан
 
DartVader
Junior Member
**
Отсутствует


1C++ rocks!

Сообщений: 29
Зарегистрирован: 13. Марта 2015
Re: Вывод справочника в соответствии с иерархией групп
Ответ #3 - 15. Мая 2017 :: 19:46
Печать  
Класс ! буду пробовать на основании того что ты выложил. Индексированные таблицы поидее знаю как использовать, она группирует с потомками, это проба пера с результатом а 0,2 секунды на все....
  
Наверх
 
IP записан
 
DartVader
Junior Member
**
Отсутствует


1C++ rocks!

Сообщений: 29
Зарегистрирован: 13. Марта 2015
Re: Вывод справочника в соответствии с иерархией групп
Ответ #4 - 15. Мая 2017 :: 19:51
Печать  
s1.ISFOLDER||s1.DESCR - > не понял SQL конструкцию..куда копать?
  
Наверх
 
IP записан
 
Djelf
God Member
*****
Отсутствует


Ubuntu + wine@etersoft
+ 1C 7.7

Сообщений: 634
Местоположение: Питер
Зарегистрирован: 02. Ноября 2007
Пол: Мужской
Re: Вывод справочника в соответствии с иерархией групп
Ответ #5 - 15. Мая 2017 :: 20:10
Печать  
У sqlite || это сложение строк. Возможно как то и можно сделать сортировку красивее но пока не догадался как.

Пример дерева и работы с ним средствами 1sqlite тут https://cloud.mail.ru/public/uQLv/QQkBGQxSu
Для mssql что то сильно похожее должно быть.
  
Наверх
www  
IP записан
 
DartVader
Junior Member
**
Отсутствует


1C++ rocks!

Сообщений: 29
Зарегистрирован: 13. Марта 2015
Re: Вывод справочника в соответствии с иерархией групп
Ответ #6 - 16. Мая 2017 :: 07:28
Печать  
Переделал твой запрос в MS SQL 'He is alive!':

WITH Parts(ParentID, ID, goodsLevel, ord) as
(      SELECT
           mainGoods.ParentID,
           mainGoods.ID, 0 goodsLevel,
           CAST((LTRIM(RTRIM(mainGoods.ISFOLDER)) + LTRIM(RTRIM(ISNULL(mainGoods.DESCR,'')))) as nvarchar(max)) ord
    FROM
           SC14 mainGoods
    WHERE
           mainGoods.ISFolder = 1 AND mainGoods.ParentID = '     0   '
    UNION ALL 
    SELECT
           childGoods.ParentID,
           childGoods.ID,
           goodsLevel + 1,
           (p.ord + LTRIM(RTRIM(childGoods.ISFOLDER)) + LTRIM(RTRIM(ISNULL(childGoods.DESCR,'')))) ord
    FROM SC14 childGoods
        INNER JOIN Parts p 
        ON childGoods.ParentID = p.ID AND childGoods.ISFolder = 1


SELECT ParentID , ID, goodsLevel , ord
FROM Parts
ORDER BY ord
  
Наверх
 
IP записан
 
Djelf
God Member
*****
Отсутствует


Ubuntu + wine@etersoft
+ 1C 7.7

Сообщений: 634
Местоположение: Питер
Зарегистрирован: 02. Ноября 2007
Пол: Мужской
Re: Вывод справочника в соответствии с иерархией групп
Ответ #7 - 16. Мая 2017 :: 07:41
Печать  
DartVader писал(а) 16. Мая 2017 :: 07:28:
Переделал твой запрос в MS SQL 'He is alive!':

trim`ы не нужны, там полная строка должна быть, иначе сортировка сбивается. И сортировку я делаю внутри cte т.е. на клиент она не должна передаваться и должна оставаться где то там внутри.
  
Наверх
www  
IP записан
 
DartVader
Junior Member
**
Отсутствует


1C++ rocks!

Сообщений: 29
Зарегистрирован: 13. Марта 2015
Re: Вывод справочника в соответствии с иерархией групп
Ответ #8 - 16. Мая 2017 :: 08:00
Печать  
Не в SQL не дает сортировку внутри пробовал...тримы уберем...хотя вроде правильно все...оно ж с попы пробелы убирает чего должна сбиватся сортировка?
  
Наверх
 
IP записан
 
Djelf
God Member
*****
Отсутствует


Ubuntu + wine@etersoft
+ 1C 7.7

Сообщений: 634
Местоположение: Питер
Зарегистрирован: 02. Ноября 2007
Пол: Мужской
Re: Вывод справочника в соответствии с иерархией групп
Ответ #9 - 16. Мая 2017 :: 08:31
Печать  
Строка же складывается с уровнем
1Гвоздь2Маленький
1Гвоздь   2Маленький
Это будет разная сортировка.

Печально что сортировка внутри не работает. Эх... сколько реализаций sql столько и разных вариантов одного ответа...
  
Наверх
www  
IP записан
 
Djelf
God Member
*****
Отсутствует


Ubuntu + wine@etersoft
+ 1C 7.7

Сообщений: 634
Местоположение: Питер
Зарегистрирован: 02. Ноября 2007
Пол: Мужской
Re: Вывод справочника в соответствии с иерархией групп
Ответ #10 - 06. Апреля 2018 :: 16:57
Печать  
Djelf писал(а) 16. Мая 2017 :: 08:31:
Печально что сортировка внутри не работает. Эх... сколько реализаций sql столько и разных вариантов одного ответа...


Кажется я вообще ничего не понимаю в сортировке Подмигивание

Выше я привел пример запроса со склеиванием строк для сортировки дерева. http://www.1cpp.ru/forum/YaBB.pl?num=1494875208/1#1

Ну вот дошло, наконец, как до жирафа, как без склейки...

Склейка все таки лишнюю память кушает, да и запрос стал на ~30% быстрее.

Код (SQL)
Выбрать все
	WITH cte(id,parentid,level,isfolder,isviewed,descr)
	AS (
		SELECT
			s1.ID, s1.PARENTID, 1, s1.ISFOLDER,1, s1.DESCR
		FROM Справочник_Номенклатура AS s1
		WHERE s1.PARENTID =  '     0   '

		UNION ALL
		SELECT
			s2.ID, s2.PARENTID, cte.LEVEL+1, s2.ISFOLDER, 0,s2.DESCR
		FROM Справочник_Номенклатура AS s2
	    INNER JOIN cte ON cte.ID=s2.PARENTID
		WHERE cte.ISFOLDER=1

		ORDER BY 3 DESC,4 ASC,6 ASC -- level,isfolder,descr
               
	)
--	INSERT INTO tree(parentid,id,level,isfolder,isviewed)
	SELECT
		cte.parentid [Родитель $Справочник.Номенклатура],
		cte.id  [Номенклатура $Справочник.Номенклатура],
		cte.level,
		cte.isfolder,
		cte.isviewed
	FROM cte
 



P.S. этот запрос для sqlite.
  
Наверх
www  
IP записан
 
Переключение на Главную Страницу Страницы: 1
ОтправитьПечать