powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Агрегация сумм в иерархических запросах
63 сообщений из 63, показаны все 3 страниц
Агрегация сумм в иерархических запросах
    #36726954
chameleon82
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Всех приветствую, возник такой вопрос, необходимо сагрегировать суммы в иерархическом запросе. Имеется некая иерархия: "Блоки/Контрагенты/Статьи/Счета", иерархия настроена определенным образом как этого хочет видеть заказчик.
Соответственно, при присоединении данных к иерархии суммы в рублях у меня находятся в самых нижних уровнях иерархии. Задача - получить агрегированные суммы по иерархии.
Например, я делаю селект:
Код: plaintext
1.
2.
3.
4.
SELECT lpad(' ',(level- 1 )* 5 )||description , amount
FROM XX_BDR_HIER_V v
CONNECT BY PRIOR flex_value = parent_flex_value
START WITH parent_flex_value is null 

и получаю нечто вроде:

Код: plaintext
1.
2.
3.
4.
5.
Блок инвестиционные расходы		 0 
     Технические расходы		 0 
         Статья  1 			 2000 
         Статья  2 			 3000 
     Прочие расходы			 1000 

А хотелось бы
Код: plaintext
1.
2.
3.
4.
5.
Блок инвестиционные расходы		 6000 
     Технические расходы		 5000 
         Статья  1 			 2000 
         Статья  2 			 3000 
     Прочие расходы			 1000 

Притом, гонять иерархию на расчет каждой суммы (сумма иерархии от парент-нода текущей строки в иерархии) не хотелось бы - увеличение времени работы сложного запроса, практика показала, что на больших данных могут еще и нехорошие ошибки вываливаться.
Также не пойдет метод джоина с группировкой по каждой строке иерархии по полям Блок/контрагент/статьи/счета, т.к. могут быть сложные правила соединения (например, по определенным дополнительным условиям данные попадают в другой блок), а потом заворачивание на иерархию.

Самым простым я тут вижу написание функции по типу sys_connect_by_path, но суммирующую суммы с дочерних нодов (допускается с суммой текущего нода для простоты). Но чтото не могу сообразить как это сделать. Помогите разобраться :)
Пс: Oracle 9i
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36727024
Фотография -2-
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
chameleon82,

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
with t as (
   select  1  id, null parent_id, 'Top' description,  0  amount from dual union all
   select  2  id,  1  parent_id, 'Top-One' description,  0  amount from dual union all
   select  3  id,  2  parent_id, 'One-one' description,  2000  amount from dual union all
   select  4  id,  2  parent_id, 'One-two' description,  3000  amount from dual union all
   select  5  id,  1  parent_id, 'Top-Two' description,  1000  amount from dual 
)
select *
from t
start with parent_id is null
connect by prior id = parent_id
model 
dimension by (id, parent_id, rownum r)
measures(amount)
rules (
   amount[any, any, any] order by r desc = nvl(amount[cv(), cv(), cv()], 0 ) + nvl(sum(amount)[any, cv(id), any], 0 )
)
+апгрейд до 10g.
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36727052
Вложенный деревянный запрос:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
-- Тестовые данные:
with XX_BDR_HIER_V as (
   select  1  flex_value, null parent_flex_value, 'Top' description,  0  amount from dual union all
   select  2  flex_value,  1  parent_flex_value, 'Top-One' description,  0  amount from dual union all
   select  3  flex_value,  2  parent_flex_value, 'One-one' description,  2000  amount from dual union all
   select  4  flex_value,  2  parent_flex_value, 'One-two' description,  3000  amount from dual union all
   select  5  flex_value,  1  parent_flex_value, 'Top-Two' description,  1000  amount from dual 
)
--
--
-- Основной запрос:
SELECT lpad(' ',(level- 1 )* 5 )||description as description, amount,
       (
         select sum(amount) 
           from XX_BDR_HIER_V z
          start with z.flex_value = v.flex_value
        connect by prior flex_value = parent_flex_value
       ) as total_amount
  FROM XX_BDR_HIER_V v
CONNECT BY PRIOR flex_value = parent_flex_value
 START WITH parent_flex_value is null 


Query finished, retrieving results...

   DESCRIPTION        AMOUNT     TOTAL_AMOUNT
-----------------     ------     ------------
Top                         0               6000 
     Top-One                0               5000 
          One-one        2000               2000 
          One-two        3000               3000 
     Top-Two             1000               1000 

 5  row(s) retrieved
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36727247
chameleon82
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
-2-, к сожалению апгрейд исключен. Продакшен сервер с офф.поддержкой, на 10ку нет денег.

2Добрый Э-эх. Я изначально решил задачу точно таким же методом, но, к сожалению, время работы его заметно увеличилось, при больших объемах вываливается too old snapshot или еще какая-нибудь нехорошая вещь. Материализовать подзапрос также не предоставляется возможным изза вероятности выпадения ошибки нехватки temp.
Поэтому нужно какое-нибудь элегантное решение. Есть конечно вариант через промежуточную temp таблицу, но очень хотелось бы без нее.
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36727259
ALocky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
chameleon82,

Почему бы не хранить нужные тебе суммы в той же таблице? Один раз столбец просчитаешь, дальше выборка будет мгновенная.
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36727285
Фотография -2-
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
chameleon82,

Если уровень вложенности ограничен udf_evaluate(sys_connect_by_path(amount, '+'))
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36727294
chameleon82
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Alocky,
Иерархия - это наборы значений, там свои поля добавлять нельзя - да и не нужно это - т.к. система многопользовательская.
Реальные данные, которые соединяются с этой иерархией, сгруппированные данные порядка мильона строк. Фактически эти сгруппированные данные - это еще один более нижний уровень, т.к. пользователь может запросить и детализацию (в разных блоках группировка по разным критериям может быть).

Хотя есть вариант, на который вы меня навели: сделать временную таблицу, в нее сгрузить и иерархию, и сгруппированные данные со ссылкой на парент_ид, потом все это завернуть в отчет. Однако это не решает моей задачи. Пересчет каждого нода все равно надо делать :) Хотя в данном случае snapshoot too old практически сводится к минимальным шансам.
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36727316
ALocky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
chameleon82
Иерархия - это наборы значений, там свои поля добавлять нельзя - да и не нужно это - т.к. система многопользовательская.

Что-то связи не увидел

chameleon82 Пересчет каждого нода все равно надо делать
Конечно надо, кто ж спорит. Решать это можно по-разному, тут от задачи зависит. Общих рекомендаций, думаю, не существует.
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36727332
chameleon82
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
-2-chameleon82,

Если уровень вложенности ограничен udf_evaluate(sys_connect_by_path(amount, '+'))

Нет функции udf_evaluate, google не помогает :( Что это за функция? Если суммы собираются с нижних уровней к верхним, то в качестве решения пойдет. Уровень вложенности не более 5-6ти, так что в этом плане так же пойдет.
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36727351
chameleon82
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ALockychameleon82
Иерархия - это наборы значений, там свои поля добавлять нельзя - да и не нужно это - т.к. система многопользовательская.

Что-то связи не увидел


OeBS, иерархию можно получить в виде вьюшки. Если повесить поле сумма на какой-нибудь атрибут, то что произойдет, если два пользователя запустят отчет одновременно? Fail.
В общем я хотел бы решение, похожее на приведенное -2-, возможно с помощью самописной аналитической функции.
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36727361
Фотография -2-
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
chameleon82Нет функции udf_evaluate, google не помогает :( Что это за функция? Если суммы собираются с нижних уровней к верхним, то в качестве решения пойдет. Уровень вложенности не более 5-6ти, так что в этом плане так же пойдет.Что за функция, можно было догадаться из названия, но собирает она действительно сверху вниз - не подходит.
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36727367
chameleon82
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
-2-Что за функция, можно было догадаться из названия, но собирает она действительно сверху вниз - не подходит.
По названию то я догадался ), но в нашей 9i ее нет (
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36727385
andreymx
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
здесь писал лет 5 назад

используем принцип в сотнях отчетов
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36727416
Фотография orawish
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
chameleon82,

без двойной деревяшки - это так:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
select b.empno, b.ename, a.s1, a.s2 from
(select a.empno ,sum(a.sal) s1, sum(a.comm) s2
  from scott.emp a
      ,(select empno
          from scott.emp
    start with mgr is not null
   connect by prior mgr = empno) b
group by a.empno
) a, scott.emp b
where a.empno=b.empno
order by  2 ;
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36727419
Фотография -2-
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Не знаю, будет ли быстрее пять-шесть over(partition by ...)
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
with t as ( --id - уникальны
   select  1  id, null parent_id, 'Top' description,  10  amount from dual union all
   select  2  id,  1  parent_id, 'Top-One' description,  100  amount from dual union all
   select  3  id,  2  parent_id, 'One-one' description,  2000  amount from dual union all
   select  4  id,  2  parent_id, 'One-two' description,  3000  amount from dual union all
   select  5  id,  1  parent_id, 'Top-Two' description,  1000  amount from dual union all
   select  4  id,  2  parent_id, 'One-three' description,  300  amount from dual 
)
select id, description, amount, 
   case l 
      when  1  then sum(amount) over(partition by p1)
      when  2  then sum(amount) over(partition by p2)
      when  3  then sum(amount) over(partition by p3)
      when  4  then sum(amount) over(partition by p4)
      when  5  then sum(amount) over(partition by p5)
   end ha
from (
select level l, id, parent_id, description, amount, 
sys_connect_by_path(id,'/') p,
substR(sys_connect_by_path(id,'/'),  1 ,  1 * 2 ) p1,
substR(sys_connect_by_path(id,'/'),  1 ,  2 * 2 ) p2,
substR(sys_connect_by_path(id,'/'),  1 ,  3 * 2 ) p3,
substR(sys_connect_by_path(id,'/'),  1 ,  4 * 2 ) p4,
substR(sys_connect_by_path(id,'/'),  1 ,  5 * 2 ) p5
from t
start with parent_id is null
connect by prior id = parent_id
) tt;
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36727422
Фотография -2-
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
-2-,

sys_connect_by_path(id,'/') -> sys_connect_by_path('*','/')
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36727428
Фотография -2-
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
-2-,

черт... в общем, выровнять id на фиксированную длину
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36727733
chameleon82
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
В общем придумал такую вещь :)
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
select lpad(' ',(level- 1 )* 5 )||t.job hier
	 , sal
     , (select extractvalue(a.column_value, '/*/*/*') from table(xmlsequence(dbms_xmlgen.getXMLtype('select '||t.summ||' column_value from dual a')))a)
	   sal_summ   
from (
select ( '0'||sys_connect_by_path(sal,'+') ) summ
    , e.* from scott.emp e
start with mgr is not null
connect by prior mgr = empno
) t
start with mgr is null
connect by mgr = prior empno
order siblings by job
Теперь осталось это прикрутить как-нибудь к реальным данным. Все же мне кажется, в любом случае придется использовать global temporary table. Но похоже, гадких ошибок уже не будет.
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36727782
chameleon82
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
^^^
Кстати, в этом виде все равно просчитывается для каждого нода :( а используются ли повторно вычисленные значения по иерархии - не знаю как проверить? Если да - то замечательно, если нет, то видимо все равно тормоза будут. Пс: в реальной иерархии порядка 50-100 нодов, с детализацией может быть до 1000.
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36727939
Фотография -2-
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Без анала и моделей:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
with t as ( 
   select  1  id, null parent_id, 'Top' description,  10  amount from dual union all
   select  2  id,  1  parent_id, 'Top-One' description,  100  amount from dual union all
   select  3  id,  2  parent_id, 'One-one' description,  2000  amount from dual union all
   select  4  id,  2  parent_id, 'One-two' description,  3000  amount from dual union all
   select  5  id,  1  parent_id, 'Top-Two' description,  1000  amount from dual union all
   select  6  id,  2  parent_id, 'One-three' description,  300  amount from dual 
)
select 
   min(id) keep(dense_rank first order by l) id,
   min(description) keep(dense_rank first order by l) description,
   sum(amount)
from (
     select level l, id, parent_id, description, amount, 
     sys_connect_by_path(id,'/') p,
     std.subword(sys_connect_by_path(id,'/'),  1 ) p1,
     std.subword(sys_connect_by_path(id,'/'),  2 ) p2,
     std.subword(sys_connect_by_path(id,'/'),  3 ) p3,
     std.subword(sys_connect_by_path(id,'/'),  4 ) p4,
     std.subword(sys_connect_by_path(id,'/'),  5 ) p5 --максимальная глубина хиерархии
   from t
   start with parent_id is null
   connect by prior id = parent_id
) tt
group by p1, rollup(p2,p3,p4,p5)
having grouping_id(p2, p3, p4, p5) = power( 2 ,  5 -min(l))- 1 
;
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36727974
chameleon82
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Решение интересное
Однако std.subword - опять же с 10ки? или что за пакет? заменил на substr, вроде работает :)
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36727988
Фотография -2-
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
chameleon82Однако std.subword - опять же с 10ки?Нет еще с семерки тяну на каждую БД, где пасусь...
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36727995
Фотография -2-
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
От having можно попробовать избавиться через grouping sets, но не допер как.
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36728156
chameleon82
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
-2-От having можно попробовать избавиться через grouping sets, но не допер как.

Указать необходимые в выводе сочетания строк
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36728419
LG
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
-2-,

-2-Без анала и моделей:
Результат не верный :)
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36728529
Фотография -2-
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
LGРезультат не верный :)А тестовые данные и ожидаемый результат? Или просто ткнуть носом в ошибку?
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36728559
LG
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
-2-,

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
select 
   min(id) keep(dense_rank first order by l) id,
   min(description) keep(dense_rank first order by l) description,
   sum(amount)
from (
     select level l, id, parent_id, description, amount, 
     sys_connect_by_path(id,'/') p,
     substr(sys_connect_by_path(id,'/'),  1 ) p1,
     substr(sys_connect_by_path(id,'/'),  2 ) p2,
     substr(sys_connect_by_path(id,'/'),  3 ) p3,
     substr(sys_connect_by_path(id,'/'),  4 ) p4,
     substr(sys_connect_by_path(id,'/'),  5 ) p5 
   from t
   start with parent_id is null
   connect by prior id = parent_id
) tt
group by p1, rollup(p2,p3,p4,p5)
having grouping_id(p2, p3, p4, p5) = power( 2 ,  5 -min(l))- 1 
результат
Код: plaintext
1.
2.
3.
4.
5.
6.
   	ID	DESCRIPTION	SUM(AMOUNT)
	 1 	Top	 10 
	 2 	Top-One	 100 
	 5 	Top-Two	 1000 
	 3 	One-one	 2000 
	 4 	One-two	 3000 
	 6 	One-three	 300 
должно быть
Код: plaintext
1.
2.
3.
4.
5.
	 1 	Top	 10 	 6410 
	 2 	Top-One	 100 	 5400 
	 5 	Top-Two	 1000 	 1000 
	 4 	One-two	 3000 	 3300 
	 4 	One-three	 300 	 3300 
	 3 	One-one	 2000 	 2000 
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36728574
LG
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
LG,
Сорри, забыл
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
with t as ( 
   select  1  id, null parent_id, 'Top' description,  10  amount from dual union all
   select  2  id,  1  parent_id, 'Top-One' description,  100  amount from dual union all
   select  3  id,  2  parent_id, 'One-one' description,  2000  amount from dual union all
   select  4  id,  2  parent_id, 'One-two' description,  3000  amount from dual union all
   select  5  id,  1  parent_id, 'Top-Two' description,  1000  amount from dual union all
   select  6  id,  2  parent_id, 'One-three' description,  300  amount from dual 
)
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36728622
Фотография -2-
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
LG,

substr не тоже самое, что subword. Смысл p1..p5 - деревянный unpivot. Там должны получиться айдишники соответствующей глубины.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
SQL> with t as (
   select  1  id, null parent_id, 'Top' description,  10  amount from dual union all
   3      select  2  id,  1  parent_id, 'Top-One' description,  100  amount from dual union all
   select  33  id,  2  parent_id, 'One-one' description,  2000  amount from dual union all
   5      select  4  id,  2  parent_id, 'One-two' description,  3000  amount from dual union all
   select  5  id,  1  parent_id, 'Top-Two' description,  1000  amount from dual union all
   select  6  id,  2  parent_id, 'One-three' description,  300  amount from dual
   union all select  66  id,  6  parent_id, 'Tree-three' description,  3  amount from dual
   union all select  666  id,  66  parent_id, 'Tree-three' description,  0 . 3  amount from dual
)
  11   select 
  12      min(id) keep(dense_rank first order by l) id,
   min(description) keep(dense_rank first order by l) description,
   sum(amount),
  15      p1, p2, p3, p4, p5, grouping_id(p2, p3, p4, p5) grp, power( 2 ,  5 -min(l))- 1  pwr
  16   from (
  17        select level l, id, parent_id, description, amount,
     sys_connect_by_path(id,'/') p,
     std.subword(sys_connect_by_path(id,'/'),  1 ) p1,
  20        std.subword(sys_connect_by_path(id,'/'),  2 ) p2,
  21        std.subword(sys_connect_by_path(id,'/'),  3 ) p3,
  22        std.subword(sys_connect_by_path(id,'/'),  4 ) p4,
     std.subword(sys_connect_by_path(id,'/'),  5 ) p5 --максимальная глубина хиерархии
  24      from t
  25      start with parent_id is null
   connect by prior id = parent_id
  27   ) tt
  28   group by p1, rollup(p2,p3,p4,p5)
having grouping_id(p2, p3, p4, p5) = power( 2 ,  5 -min(l))- 1 
order by p1 nulls first, p2 nulls first, p3 nulls first, p4 nulls first, p5 nulls first
  31   ;

        ID DESCRIPTION                    SUM(AMOUNT) P1    P2    P3    P4    P5           GRP        PWR
---------- ------------------------------ ----------- ----- ----- ----- ----- ----- ---------- ----------
          1  Top                                  6413 , 3   1                                       15           15 
          2  Top-One                              5403 , 3   1       2                                  7            7 
         33  One-one                                2000   1       2       33                           3            3 
          4  One-two                                3000   1       2       4                            3            3 
          6  One-three                             303 , 3   1       2       6                            3            3 
         66  Tree-three                              3 , 3   1       2       6       66                     1            1 
        666  Tree-three                              , 3   1       2       6       66      666              0            0 
          5  Top-Two                                1000   1       5                                  7            7 

...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36728661
LG
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
-2-,
А ...
Ясно ...
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36729046
wildwind
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
chameleon82,

Можно построить транзитивное замыкание на иерархии. Тогда агрегирующие (и некоторые другие) запросы сильно упростятся. Но есть недостаток - его нужно поддерживать. Если иерархия меняется нечасто, это обычно не проблема.
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36729088
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
wildwindЕсли иерархия меняется нечасто
и при этом иерархия не слишком глубока, то еще проще заменить иерархию классификатором.
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36729132
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
column description format a20
with t as (
           select  1  id, null parent_id, 'Top' description,  10  amount from dual union all
           select  2  id,  1  parent_id, 'Top-One' description,  100  amount from dual union all
           select  3  id,  2  parent_id, 'One-one' description,  2000  amount from dual union all
           select  4  id,  2  parent_id, 'One-two' description,  3000  amount from dual union all
           select  5  id,  1  parent_id, 'Top-Two' description,  1000  amount from dual union all
           select  6  id,  2  parent_id, 'One-three' description,  300  amount from dual
          ),
     h as (
           select  id,
                   lpad(' ',level *  2 ) || description description,
                   amount,
                   sys_connect_by_path(id,'/') || '/' path,
                   rownum rn
             from  t
             start with parent_id is null
             connect by prior id = parent_id
          )
select  h1.id,
        h1.description,
        h1.amount,
        sum(h2.amount) total_amount
  from  h h1,
        h h2
  where instr(h2.path,h1.path) =  1 
  group by h1.id,
           h1.description,
           h1.amount,
           h1.rn,
        h1.amount
  order by h1.rn
/

        ID DESCRIPTION              AMOUNT TOTAL_AMOUNT
---------- -------------------- ---------- ------------
          1    Top                         10           6410 
          2      Top-One                  100           5400 
          3        One-one               2000           2000 
          4        One-two               3000           3000 
          6        One-three              300            300 
          5      Top-Two                 1000           1000 

 6  rows selected.

SQL>  

SY.
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36729149
andreymx
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
WITH
hr AS
(
SELECT  1  ID, 'Хозяин'                NAME,  0 +NULL id_parent FROM dual UNION ALL
SELECT  2  ID, 'Директор'              NAME,  1       id_parent FROM dual UNION ALL
SELECT  3  ID, 'Главный инженер'       NAME,  2       id_parent FROM dual UNION ALL
SELECT  4  ID, 'Главный бухгалтер'     NAME,  2       id_parent FROM dual UNION ALL
SELECT  5  ID, 'Главный it-специалист' NAME,  4       id_parent FROM dual
),
divs AS
(
SELECT  1  ID,  10000  summa FROM dual UNION ALL
SELECT  2  ID,   1000  summa FROM dual UNION ALL
SELECT  3  ID,    100  summa FROM dual UNION ALL
SELECT  4  ID,    150  summa FROM dual UNION ALL
SELECT  5  ID,     10  summa FROM dual
),
all_relations AS
(
SELECT ID,
       to_number(trim(',' FROM sys_connect_by_path(CASE WHEN LEVEL =  1  THEN ID END, ','))) id_first
  FROM hr
 connect BY PRIOR id_parent = ID
)
SELECT ar.ID, max(hr.NAME) NAME, sum(summa) summa
  FROM all_relations ar,
       divs,
       (
        SELECT ID,
               lpad(' ',LEVEL *  2 ) || NAME NAME
         FROM  hr
         start WITH id_parent IS NULL
         connect BY PRIOR ID = id_parent
       )hr
 WHERE divs.ID = ar.id_first
   AND hr.ID = ar.ID
 GROUP BY ar.ID
idnamesumma11__Хозяин1126022____Директор126034______Главный бухгалтер16045________Главный it-специалист1053______Главный инженер100
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36731115
chameleon82
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Последнее очень близко к истине :) Потестировал на кошках, too old snapshot`ом пока не пахнет :) Осталось дописать запрос по реальным данным.
Остался неясным вопрос, каким танственным образом выстраивается правильная иерархия, ведь во внешнем запросе нет ни слова об упорядочивании!
пс: а вообще можно ли на иерархическом запросе написать собственную анналитическую функцию, которая бы учитывала иерархию?
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36731135
chameleon82
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
-2-, можно ли выложить код функции std.subword? в интернете так и не нашел его (
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36731137
chameleon82
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
wildwindchameleon82,

Можно построить транзитивное замыкание на иерархии. Тогда агрегирующие (и некоторые другие) запросы сильно упростятся. Но есть недостаток - его нужно поддерживать. Если иерархия меняется нечасто, это обычно не проблема.
можно поподробнее?
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36731174
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
chameleon82можно поподробнее?
Транзитивное замыкание бинарного отношения R на множестве X есть наименьшее транзитивное отношение на множестве X, включающее R

Если попроще - то предлагается дополнить табличку
id parent_id2 13 24 2
следующим образом:
1->2->3 => 1,3
1->2->3->4 => 1,4
2->3->4 => 2,4
id parent_id2 13 24 21 31 42 4
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36731194
Фотография -2-
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
chameleon82-2-, можно ли выложить код функции std.subword? в интернете так и не нашел его (Она слишком универсальная и будет излишне для данной задачи греть процессор.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
with t as (
   select '/12/3/456' s from dual
),
w as (
   select level n from dual connect by level <=  5 
)
select n, 
   substr(s, instr(s, '/',  1 , n)+ 1 , instr(s||'/', '/',  1 , n+ 1 )-instr(s, '/',  1 , n)- 1 ) 
from t cross join w;
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36731253
wildwind
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andrey_anonymous следующим образом:
1->2->3 => 1,3
1->2->3->4 => 1,4
2->3->4 => 2,4
+ рефлексивность
1->1
2->2
3->3
4->4

И скорее не дополнить, а создать еще одну.
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36731267
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
wildwind
1->1
2->2
3->3
4->4
Это будет анекдот про слона, муху и вечный кайф :)
Ну а если по нашенски - то ORA-01436: CONNECT BY loop in user data
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36731299
wildwind
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andrey_anonymous,

Поэтому замыкание - отдельно. А иерархия - для иерархических запросов.
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36734953
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
На основе решения by Vladimir Sitnikov, которое основывается на граничных суммах, можно предложить более общее и простое:
Код: plaintext
with t AS\n (SELECT id, parent_id, amount, LEVEL l, rownum rn\n    FROM \n (SELECT  1  id, NULL parent_id, \'Top\' description,  10  amount\n    FROM dual\n  UNION ALL\n  SELECT  2  id,  1  parent_id, \'Top-One\' description,  100  amount\n    FROM dual\n  UNION ALL\n  SELECT  3  id,  2  parent_id, \'One-one\' description,  2000  amount\n    FROM dual\n  UNION ALL\n  SELECT  4  id,  2  parent_id, \'One-two\' description,  3000  amount\n    FROM dual\n  UNION ALL\n  SELECT  5  id,  1  parent_id, \'Top-Two\' description,  1000  amount\n    FROM dual\n  UNION ALL\n  SELECT  6  id,  2  parent_id, \'One-three\' description,  300  amount FROM dual)\n   START WITH id =  1 \n  CONNECT BY parent_id = PRIOR id)\nSELECT id,\n       parent_id,\n       amount,\n       SUM(amount) over(ORDER BY rn rows BETWEEN CURRENT ROW AND next_branch - rn -  1  following) summa\n  FROM (SELECT id,\n               parent_id,\n               amount,\n               rn,\n               nvl((SELECT MIN(rn) FROM t sub WHERE sub.l <= t.l AND sub.rn > t.rn),1e10) next_branch\n          FROM t\n         ORDER BY id) t;
Использует для определения окна rows BETWEEN, а не range BETWEEN, но поскольку содержит коррелированный подзапрос - отрабатывает медленнее, зато быстрее многих других предложенных. ;) Кроме того не содержит ограничений на глубину дерева и число непосредственных потомков.
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36735202
andreymx
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
dbms_photoshop,

моё таки круче :))

опробовано на сотнях отчетов в течение 5 лет
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #36736468
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
dbms_photoshopИспользует для определения окна rows BETWEEN, а не range BETWEEN, но поскольку содержит коррелированный подзапрос - отрабатывает медленнее, зато быстрее многих других предложенных. ;)И гораздо медленнее элементарного при наличии индекса на parent_id (а куда ж без него? :) ).
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
Агрегация сумм в иерархических запросах
    #37724201
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andreymxdbms_photoshop,

моё таки круче :))

опробовано на сотнях отчетов в течение 5 летОно может и прекрасно работает, если у тебя в таблице с иерархией пару сотен строк. А теперь представь, что в иерархии полмиллиона строк и ты сначала получаешь свои all_relations, а потом соединяешь их с иерахией.
Elicdbms_photoshopИспользует для определения окна rows BETWEEN, а не range BETWEEN, но поскольку содержит коррелированный подзапрос - отрабатывает медленнее, зато быстрее многих других предложенных. ;)И гораздо медленнее элементарного при наличии индекса на parent_id (а куда ж без него? :) ).Не если еще чуток пофантазировать можно обойтись без подзапроса:
Код: plsql
\r\nwith t as\r\n (select id, parent_id, amount, level l, rownum rn\r\n    from \r\n (select 1 id, null parent_id, \'Top\' description, 10 amount\r\n    from dual\r\n  union all\r\n  select 2 id, 1 parent_id, \'Top-One\' description, 100 amount\r\n    from dual\r\n  union all\r\n  select 3 id, 2 parent_id, \'One-one\' description, 2000 amount\r\n    from dual\r\n  union all\r\n  select 4 id, 2 parent_id, \'One-two\' description, 3000 amount\r\n    from dual\r\n  union all\r\n  select 5 id, 1 parent_id, \'Top-Two\' description, 1000 amount\r\n    from dual\r\n  union all\r\n  select 6 id, 2 parent_id, \'One-three\' description, 300 amount from dual)\r\n   start with id = 1\r\n  connect by parent_id = prior id\r\n  order siblings by id)\r\nselect id,\r\n       parent_id,\r\n       amount,\r\n       sum(amount) over(order by rn rows between current row and next_branch - rn - 1 following) summa\r\n  from (select id,\r\n               parent_id,\r\n               amount,\r\n               rn,\r\n               nvl(decode(sign,1,-- nearest node with the same level and greater rn               \r\n                                 min(rn) over (order by l+rn/1e10 range between 1e-38 following and 1 following),\r\n                                 -- next node\r\n                                 rn + 1),1e10) next_branch\r\n          from (select id, parent_id, amount, rn, l, sign(lead(l) over (order by rn) - l) sign from t) t\r\n         order by id) t;\r\n
\r\nВроде должно работать и не такое заковыристое как у Vladimir Sitnikov.
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #37724641
andreymx
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
dbms_photoshop,

предварительно покрутил, и, возможно, не всё ещё понял

добавил одну строку в исходные данные:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
WITH T AS
 (SELECT ID, parent_id, amount, LEVEL l, ROWNUM rn
    FROM 
 (SELECT 1 ID, NULL parent_id, 'Top'   description,   10 amount FROM dual UNION ALL
  SELECT 2 ID, 1 parent_id, 'Top-One'  description,  100 amount FROM dual UNION ALL
  SELECT 3 ID, 2 parent_id, 'One-one'  description, 2000 amount FROM dual UNION ALL
  SELECT 4 ID, 2 parent_id, 'One-two'  description, 3000 amount FROM dual UNION ALL
  SELECT 5 ID, 1 parent_id, 'Top-Two'  description, 1000 amount FROM dual UNION ALL
  SELECT 6 ID, 2 parent_id, 'One-three'description,  300 amount FROM dual UNION ALL
  SELECT 7 ID, 6 parent_id,   '*****'  description,    0 amount FROM dual
 )
   start WITH ID = 1
  connect BY parent_id = PRIOR ID
  ORDER SIBLINGS BY ID)
SELECT ID,
       parent_id,
       amount,
       SUM(amount) OVER(ORDER BY rn ROWS BETWEEN CURRENT ROW AND next_branch - rn - 1 FOLLOWING) summa
  FROM (SELECT ID,
               parent_id,
               amount,
               rn,
               NVL(DECODE(SIGN,1,-- nearest node with the same level and greater rn               
                                 MIN(rn) OVER (ORDER BY l+rn/1e10 RANGE BETWEEN 1E-38 FOLLOWING AND 1 FOLLOWING),
                                 -- next node
                                 rn + 1),1e10) next_branch
          FROM (SELECT ID, parent_id, amount, rn, l, SIGN(lead(l) OVER (ORDER BY rn) - l) SIGN FROM T) T
         ORDER BY ID) T;

получил:IDPARENT_IDAMOUNTSUMMA11064102110054003220002000423000300062300130076005110001000интересует сумма 1300 для строки id=6
так и надо?
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #37724790
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
dbms_photoshopВроде должно работатьБамбуковый лес:
Код: plsql
1.
2.
3.
    select 1 id, null as parent_id, 1 as amount from dual
    union all
    select level + 1, case when mod(level, 5) = 1 then 1 else level end, 1 from dual connect by level <= 15

Код: plsql
1.
ORA-01428: argument '-5' is out of range
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #37725228
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andreymxинтересует сумма 1300 для строки id=6
так и надо?Нет, это неверно.
Ищу начало следующей ветки по окну с большим rn и тем же уровнем.
А надо искать по окну с большим rn и тем же либо меньшим уровнем.
Вот из-за выделенного возникают проблемы с определением окна.
К сожалению, если в кляузе order by фигурируют два поля, то два RANGE указать нельзя, а было бы забавно. :)
Надо подумать можно ли придумать такой expression и соответствующий range, чтоб искало правильно.
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #37725593
Фотография ПЕНСИОНЕРКА
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
dbms_photoshop,
авторОно может и прекрасно работает, если у тебя в таблице с иерархией пару сотен строк. А теперь представь, что в иерархии полмиллиона строк и ты сначала получаешь свои all_relations, а потом соединяешь их с иерахией.

предпочитала подготовить полуфабрикат
--итоги по цех,участок,профессия,месяц, наименование итога, сумма во временную таблицу РАБ1, обычно текстовик для скорости, суммы округляла согласно требованию заказчика
--с РАБ1 уже требуемый отчет с
---------перекрестный, с анализом количества столбиков(обычно до 17 при отчете за год мес-кв-год)
---------условно гладкий типа количество, сумма_без_ндс,ндс, всего с ндс по позициям номенклатуры
--обычно формировала в формате НТМ для удобства просмотра броузером или печати вордом(хотя и екселем приходилось иногда открывать для удобства доводки или очень большим для ворда)
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #37726364
andreymx
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ПЕНСИОНЕРКАпредпочитала подготовить полуфабрикат
--итоги по цех,участок,профессия,месяц, наименование итога, сумма во временную таблицу РАБ1

ну, это по задаче
где-то надо, где-то и не нужно, где-то вообще не имеет смысла, а где-то через WITH
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #37832509
chameleon82
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Еще вариант. Как-то так получилось. Правда на больших обьемах данных не тестировал
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
select v, p, sum(am2) am from (
select v,p, level, xx_sql.query('select '||sys_connect_by_path('('||to_char(am)||')','+')||' from dual') am2 
from (
select 1 v , 0 p, 0 am from dual
union all
select 2 v, 1 p, 120.2 am from dual
union all
select 4 v, 2 p, -75 am from dual
union all
select 5 v, 2 p, 23 am from dual
union all
select 3 v, 1 p, 210 am from dual  
) t
connect by v = prior p
--start with p = 0 -- не указываем откуда собираем
) group by v,p


функция xx_sql.query возвращает результат первой колонки первой строки указанного запроса. можно заменить на что попроще.
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #37836285
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
chameleon82Еще вариант. Как-то так получилось. Правда на больших обьемах данных не тестировал
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
select v, p, sum(am2) am from (
select v,p, level, xx_sql.query('select '||sys_connect_by_path('('||to_char(am)||')','+')||' from dual') am2 
from (
select 1 v , 0 p, 0 am from dual
union all
select 2 v, 1 p, 120.2 am from dual
union all
select 4 v, 2 p, -75 am from dual
union all
select 5 v, 2 p, 23 am from dual
union all
select 3 v, 1 p, 210 am from dual  
) t
connect by v = prior p
--start with p = 0 -- не указываем откуда собираем
) group by v,p


функция xx_sql.query возвращает результат первой колонки первой строки указанного запроса. можно заменить на что попроще.Не совсем понятна затея строить всё из всех, чтоб потом тупо схлопнуть, но в своей функции здесь нет особой необходимости.
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
select v, p, 
       xmlcast(xmlquery(max(sys_connect_by_path(am,'+')) returning content) as number) result,
       max(sys_connect_by_path(am,'+')) str
from (
select 1 v , 0 p, 0 am from dual
union all
select 2 v, 1 p, 120.2 am from dual
union all
select 4 v, 2 p, -75 am from dual
union all
select 5 v, 2 p, 23 am from dual
union all
select 3 v, 1 p, 210 am from dual  
) t
connect by v = prior p
--start with p = 0
group by v,p
order by 1
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #37836305
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
chameleon82,

Впрочем, и тебе и мне можно было предварительно сделать поиск и найти примерно это .
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #37836339
andreymx
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
как минимум надо не забывать, что макс длина результата sys_connect_by_path = 4000
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #38000032
chameleon82
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Чуть выше ошибочка была. Для Oracle >= 11.2.0.2, правда с ограничением
andreymxкак минимум надо не забывать, что макс длина результата sys_connect_by_path = 4000
возможен такой код
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
select id, parent_id
, max(level)
, xmlcast(xmlquery( listagg( sys_connect_by_path(s,'+')
          ) WITHIN GROUP (ORDER BY null)
          returning content) as number)
           amount
 from (
select 1 id, null parent_id, 0 s from dual
union all
select 2 id, 1 parent_id, 0 s from dual
union all
select 3 id, 1 parent_id, 0 s from dual
union all
select 4 id, 2 parent_id, 20 s from dual
union all
select 5 id, 2 parent_id, 50 s from dual
union all
select 6 id, 3 parent_id, 40 s from dual
union all
select 7 id, 3 parent_id, 10 s from dual
) t 
connect by prior parent_id =  id
group by id,parent_id 



и опять же на 11-ом, но уже цивилизованный обход
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
WITH
  tbl AS ( select 1 id, null parent_id, 0 s from dual
              union all
              select 2 id, 1 parent_id, 0 s from dual
              union all
              select 3 id, 1 parent_id, 0 s from dual
              union all
              select 4 id, 2 parent_id, 20 s from dual
              union all
              select 5 id, 2 parent_id, 50 s from dual
              union all
              select 6 id, 3 parent_id, 40 s from dual
              union all
              select 7 id, 3 parent_id, 10 s from dual
),   
  hier (id, parent_id, amount, lvl) AS
  (
select t.id, t.parent_id, t.s, 0 lvl 
from tbl t
union all
select t.id, t.parent_id, nvl(t.s,0) + nvl(c.amount,0), c.lvl+1 
from tbl t inner join hier c on (t.id = c.parent_id)
  )
SEARCH DEPTH FIRST BY id SET order1
SELECT id , parent_id, sum(amount), max(lvl) mgrLevel, max(order1) ord
FROM hier
GROUP BY id, parent_id
ORDER BY ord DESC
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
Агрегация сумм в иерархических запросах
    #38468139
sim_tom
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
chameleon82,

все тут хорошо, до тех пор, пока не появляются родители, у которых есть свои суммы, которые надо приплюсовать к дочерним
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #38468420
Фотография orawish
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
sim_tomchameleon82,

все тут хорошо, до тех пор, пока не появляются родители, у которых есть свои суммы, которые надо приплюсовать к дочерним
вас затрудняет сложить два числа ?
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #38468662
Фотография ПЕНСИОНЕРКА
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
sim_tom,
авторвсе тут хорошо, до тех пор, пока не появляются родители, у которых есть свои суммы, которые надо приплюсовать к дочерним

только бы это --ерунда
хуже, когда есть еще и в том числе
статьясуммапо заводу100т--по цехам 60-----в том числе основным20--по соцсфере40
по цехам всего\
по основным
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #38469341
chameleon82
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ПЕНСИОНЕРКА,

а тут что сложного?
делаете "в том числе" и "не в том числе", в конечном выводе скрываете "не в том числе". тут все в настройках иерархии, либо на ноде вообще дочерние не складывать, либо расчитывать все дочерние суммы и не расчитывать или игнорировать расчет на конкретном ноде.
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
Агрегация сумм в иерархических запросах
    #38871105
StayAtHome
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
chameleon82и опять же на 11-ом, но уже цивилизованный обход
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
WITH
  tbl AS ( select 1 id, null parent_id, 0 s from dual
              union all
              select 2 id, 1 parent_id, 0 s from dual
              union all
              select 3 id, 1 parent_id, 0 s from dual
              union all
              select 4 id, 2 parent_id, 20 s from dual
              union all
              select 5 id, 2 parent_id, 50 s from dual
              union all
              select 6 id, 3 parent_id, 40 s from dual
              union all
              select 7 id, 3 parent_id, 10 s from dual
),   
  hier (id, parent_id, amount, lvl) AS
  (
select t.id, t.parent_id, t.s, 0 lvl 
from tbl t
union all
select t.id, t.parent_id, nvl(t.s,0) + nvl(c.amount,0), c.lvl+1 
from tbl t inner join hier c on (t.id = c.parent_id)
  )
SEARCH DEPTH FIRST BY id SET order1
SELECT id , parent_id, sum(amount), max(lvl) mgrLevel, max(order1) ord
FROM hier
GROUP BY id, parent_id
ORDER BY ord DESC


Очень заинтересовал пример с рекурсией, но в случае ненулевых значений у рождителей - они задваиваются в общей сумме:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
WITH
  tbl AS ( SELECT 1 ID, NULL parent_id, 0 s FROM dual
              UNION ALL
              SELECT 2 ID, 1 parent_id, 1 s FROM dual
              UNION ALL
              SELECT 3 ID, 1 parent_id, 0 s FROM dual
              UNION ALL
              SELECT 4 ID, 2 parent_id, 1 s FROM dual
              UNION ALL
              SELECT 5 ID, 2 parent_id, 1 s FROM dual
              UNION ALL
              SELECT 6 ID, 3 parent_id, 1 s FROM dual
              UNION ALL
              SELECT 7 ID, 3 parent_id, 1 s FROM dual
              UNION ALL
              SELECT 8 ID, 4 parent_id, 1 s FROM dual
),   
  hier (ID, parent_id, amount, lvl) AS
  (
SELECT T.ID, T.parent_id, T.s, 0 lvl 
FROM tbl T
UNION ALL
SELECT T.ID, T.parent_id, nvl(T.s,0) + nvl(c.amount,0), c.lvl+1 
FROM tbl T INNER JOIN hier c ON (T.ID = c.parent_id)
  )
SEARCH DEPTH FIRST BY ID SET order1
SELECT ID , parent_id, sum(amount), max(lvl) mgrLevel, max(order1) ord
FROM hier
GROUP BY ID, parent_id
ORDER BY ord DESC


Для простоты проверки положил s=1 для всех узлов? Пролучаю для узла 2 сумму "8" а не "4":
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
ID PARENT_ID SUM(AMOUNT) MGRLEVEL ORD
1		10	3	21
2	1	8	2	20
4	2	3	1	19
8	4	1	0	18
3	1	2	1	16
7	3	1	0	15
6	3	1	0	12
5	2	1	0	9


Никак сам не могу побороть - это вообще реально?
...
Рейтинг: 0 / 0
Агрегация сумм в иерархических запросах
    #38871142
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
StayAtHomeНикак сам не могу побороть - это вообще реально?Потому что нужно поменьше ненужной фантазии, когда можно тупо в лоб
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
 19  ( select connect_by_root id as id, connect_by_root parent_id as parent_id, s
 20      from tbl
 21      connect by parent_id = prior id
 22  )
 23  select id , parent_id, sum(s) as s
 24    from hier
 25    group by id, parent_id
 26    order by id
 27  ;

         ID  PARENT_ID          S
----------- ---------- ----------
          1                     6
          2          1          4
          3          1          2
          4          2          2
          5          2          1
          6          3          1
          7          3          1
          8          4          1

8 rows selected.
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
Агрегация сумм в иерархических запросах
    #39462772
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
У кого есть в наличии 12.2 можете попробовать выполнить с закоментированным правилом вместо активного
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
with t(id, parent_id, description, amount) as
(
  select 1 id, null, 'top', 10  from dual
  union all select 2, 1, 'top-one', 100 from dual
  union all select 3, 2, 'one-one', 2000 from dual
  union all select 4, 2, 'one-two', 3000 from dual
  union all select 5, 1, 'top-two', 1000 from dual
  union all select 6, 2, 'one-three', 300 from dual
  union all select 7, 6, 'three-one', 1 from dual
)
, h as
(
  select id, parent_id, description, amount, level l, rownum rn
    from t
   start with id = 1
 connect by parent_id = prior id
)
select *
  from (select h.*,
               power(2 * 10, 1 - l) x,
               sum(power(2 * 10, 1 - l)) over(order by rn) s
          from h) h0
match_recognize
(
  order by rn
  measures
    first (id) as id,
    first (parent_id) as parent_id,
    first (l) as l,
    first (rn) as rn,
    first (amount) as amount,
    final count(*)-1 cnt_children,
    final sum(amount) h_sum
  one row per match
  after match skip to next row
  pattern (y+)
  define
    y as sum(x) < 2 * first(x)
    --ORA-03113, 12.1.0.2
    --y as max(s) - min(s) < first(x)
) mr;

        ID  PARENT_ID          L         RN     AMOUNT CNT_CHILDREN      H_SUM
---------- ---------- ---------- ---------- ---------- ------------ ----------
         1                     1          1         10            6       6411
         2          1          2          2        100            4       5401
         3          2          3          3       2000            0       2000
         4          2          3          4       3000            0       3000
         6          2          3          5        300            1        301
         7          6          4          6          1            0          1
         5          1          2          7       1000            0       1000

7 rows selected.



С all rows вместо one row все ок, но все строки для каждого матча здесь не нужны.
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
with t(id, parent_id, description, amount) as
(
  select 1 id, null, 'top', 10  from dual
  union all select 2, 1, 'top-one', 100 from dual
  union all select 3, 2, 'one-one', 2000 from dual
  union all select 4, 2, 'one-two', 3000 from dual
  union all select 5, 1, 'top-two', 1000 from dual
  union all select 6, 2, 'one-three', 300 from dual
  union all select 7, 6, 'three-one', 1 from dual
)
, h as
(
  select id, parent_id, description, amount, level l, rownum rn
    from t
   start with id = 1
 connect by parent_id = prior id
)
select *
  from (select h.*,
               power(2 * 10, 1 - l) x,
               sum(power(2 * 10, 1 - l)) over(order by rn) s
          from h) h0
match_recognize
(
  order by rn
  measures
    final count(*)-1 cnt_children,
    final sum(amount) h_sum,
    count(*) cnt
  all rows per match
  after match skip to next row
  pattern (y+)
  define
    y as max(s) - min(s) < first(x)
) mr
where cnt = 1;

        RN CNT_CHILDREN      H_SUM        CNT         ID  PARENT_ID DESCRIPTI     AMOUNT          L          X          S
---------- ------------ ---------- ---------- ---------- ---------- --------- ---------- ---------- ---------- ----------
         1            6       6411          1          1            top               10          1          1          1
         2            4       5401          1          2          1 top-one          100          2        .05       1.05
         3            0       2000          1          3          2 one-one         2000          3      .0025     1.0525
         4            0       3000          1          4          2 one-two         3000          3      .0025      1.055
         5            1        301          1          6          2 one-three        300          3      .0025     1.0575
         6            0          1          1          7          6 three-one          1          4    .000125   1.057625
         7            0       1000          1          5          1 top-two         1000          2        .05   1.107625

7 rows selected.
...
Рейтинг: 0 / 0
63 сообщений из 63, показаны все 3 страниц
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Агрегация сумм в иерархических запросах
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]