Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Агрегация сумм в иерархических запросах / 25 сообщений из 63, страница 1 из 3
07.07.2010, 08:22
    #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
07.07.2010, 09:19
    #36727024
-2-
-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
07.07.2010, 09:35
    #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
07.07.2010, 10:41
    #36727247
chameleon82
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Агрегация сумм в иерархических запросах
-2-, к сожалению апгрейд исключен. Продакшен сервер с офф.поддержкой, на 10ку нет денег.

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

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

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

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

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

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

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

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

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


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

используем принцип в сотнях отчетов
...
Рейтинг: 0 / 0
07.07.2010, 11:32
    #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
07.07.2010, 11:33
    #36727419
-2-
-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
07.07.2010, 11:34
    #36727422
-2-
-2-
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Агрегация сумм в иерархических запросах
-2-,

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

черт... в общем, выровнять id на фиксированную длину
...
Рейтинг: 0 / 0
07.07.2010, 13:00
    #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
07.07.2010, 13:10
    #36727782
chameleon82
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Агрегация сумм в иерархических запросах
^^^
Кстати, в этом виде все равно просчитывается для каждого нода :( а используются ли повторно вычисленные значения по иерархии - не знаю как проверить? Если да - то замечательно, если нет, то видимо все равно тормоза будут. Пс: в реальной иерархии порядка 50-100 нодов, с детализацией может быть до 1000.
...
Рейтинг: 0 / 0
07.07.2010, 13:51
    #36727939
-2-
-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
07.07.2010, 14:02
    #36727974
chameleon82
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Агрегация сумм в иерархических запросах
Решение интересное
Однако std.subword - опять же с 10ки? или что за пакет? заменил на substr, вроде работает :)
...
Рейтинг: 0 / 0
07.07.2010, 14:08
    #36727988
-2-
-2-
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Агрегация сумм в иерархических запросах
chameleon82Однако std.subword - опять же с 10ки?Нет еще с семерки тяну на каждую БД, где пасусь...
...
Рейтинг: 0 / 0
07.07.2010, 14:10
    #36727995
-2-
-2-
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Агрегация сумм в иерархических запросах
От having можно попробовать избавиться через grouping sets, но не допер как.
...
Рейтинг: 0 / 0
07.07.2010, 15:09
    #36728156
chameleon82
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Агрегация сумм в иерархических запросах
-2-От having можно попробовать избавиться через grouping sets, но не допер как.

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

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


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