Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Нарастающий итог (агрегированные суммы) по иерархии с применением фактора / 10 сообщений из 10, страница 1 из 1
08.09.2017, 14:46
    #39518226
Нарастающий итог (агрегированные суммы) по иерархии с применением фактора
Добрый день,

имеется иерархия:


Код: 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.
SELECT 
       rn,
       material,
       hier.KOMPONENTE,
       path,
       Measure,
       faktor,
       isleaf,
       LEVEL_,
       KOMPONENTE_HIER,
       root
FROM
(
            SELECT rownum as rn,
                   material,
                   KOMPONENTE, 
                   CONNECT_BY_ROOT komponente as   root,
                   cast(SYS_CONNECT_BY_PATH(komponente,'/') as varchar2(40)) as path,
                   cast(LPAD(' ',3*(LEVEL-1))||KOMPONENTE as varchar2(20)) as KOMPONENTE_HIER,
                   Measure,
                   CONNECT_BY_ISLEAF isleaf,       
                   level as LEVEL_
             from STAMM_HIER
                 START WITH MATERIAL is NULL
                 CONNECT BY NOCYCLE  PRIOR KOMPONENTE =  MATERIAL
                 order by 1
) hier, STAMM_HIER_FAKTOR fak
where hier.komponente = fak.komponente (+)



Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
        RN MATERIAL     KOMPONENTE   PATH                                        MEASURE     FAKTOR     ISLEAF     LEVEL_ KOMPONENTE_HIER      ROOT        
---------- ------------ ------------ ---------------------------------------- ---------- ---------- ---------- ---------- -------------------- ------------
         1              12345        /12345                                           20          4          0          1 12345                12345       
         2 12345        718749       /12345/718749                                     2          5          0          2    718749            12345       
         3 718749       730014       /12345/718749/730014                              2          1          0          3       730014         12345       
         4 730014       809579       /12345/718749/730014/809579                       5          2          0          4          809579      12345       
         5 809579       111111       /12345/718749/730014/809579/111111                1                     1          5             111111   12345       
         6 809579       222222       /12345/718749/730014/809579/222222                1                     1          5             222222   12345       
         7 809579       798808       /12345/718749/730014/809579/798808                4                     1          5             798808   12345       
         8 12345        718750       /12345/718750                                     9          3          0          2    718750            12345       
         9 718750       111111       /12345/718750/111111                              1                     1          3       111111         12345       
        10 718750       222222       /12345/718750/222222                              1                     1          3       222222         12345       
        11 718750       809579       /12345/718750/809579                              5          2          0          3       809579         12345       
        12 809579       111111       /12345/718750/809579/111111                       1                     1          4          111111      12345       
        13 809579       222222       /12345/718750/809579/222222                       1                     1          4          222222      12345       
        14 809579       798808       /12345/718750/809579/798808                       4                     1          4          798808      12345       

14 rows selected.

Как подсчитать нарастающий итог по "measure" с применением фактора (measure * faktor)?
Фактор нужно применять при isleaf = 0. Затем итог выражения SUM(measure) * faktor использовать дальше для подсчета нарастающего итога следующих элементов. При подсчете нарастающего итога двигаться нужно от isleaf = 1 к root.

Попытался в Excel отразить пример подсчета.
Также прилагаю скрипты с примерами.
Заранее спасибо!

Код: 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.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
drop table STAMM_HIER;
create table STAMM_HIER
( ID NUMBER,
MATERIAL varchar2(12),
KOMPONENTE varchar2(12),
MEASURE number
);

Insert into STAMM_HIER
   (ID, MATERIAL, KOMPONENTE, MEASURE)
 Values
   (1,'12345', '718749', 2);
Insert into STAMM_HIER
   (ID, MATERIAL, KOMPONENTE, MEASURE)
 Values
   (2, '718750', '222222', 1);
Insert into STAMM_HIER
   (ID, MATERIAL, KOMPONENTE, MEASURE)
 Values
   (3, '730014', '809579', 5);
Insert into STAMM_HIER
   (ID, MATERIAL, KOMPONENTE, MEASURE)
 Values
   (4, '718750', '111111', 1);
Insert into STAMM_HIER
   (ID, MATERIAL, KOMPONENTE, MEASURE)
 Values
   (5, '809579', '222222', 1);
Insert into STAMM_HIER
   (ID, MATERIAL, KOMPONENTE, MEASURE)
 Values
   (6, '718750', '809579', 5);
Insert into STAMM_HIER
   (ID, MATERIAL, KOMPONENTE, MEASURE)
 Values
   (7, '12345', '718750', 9);
Insert into STAMM_HIER
   (ID, MATERIAL, KOMPONENTE, MEASURE)
 Values
   (8, '809579', '111111', 1);
Insert into STAMM_HIER
  (ID, MATERIAL, KOMPONENTE, MEASURE)
 Values
   (9, '718749', '730014', 2);
Insert into STAMM_HIER
   (ID, MATERIAL, KOMPONENTE, MEASURE)
 Values
   (10, '809579', '798808', 4);
Insert into STAMM_HIER
  (ID, MATERIAL, KOMPONENTE, MEASURE)
 Values
   (11, NULL,'12345', 20);
COMMIT;

drop table STAMM_HIER_FAKTOR;
CREATE TABLE STAMM_HIER_FAKTOR
(
  KOMPONENTE  VARCHAR2(12 BYTE),
  FAKTOR      NUMBER
);


CREATE UNIQUE INDEX STAMM_HIER_FAKTOR_PK ON STAMM_HIER_FAKTOR
(KOMPONENTE);
     

ALTER TABLE STAMM_HIER_FAKTOR ADD (
  CONSTRAINT STAMM_HIER_FAKTOR_PK
  PRIMARY KEY
  (KOMPONENTE)
  USING INDEX STAMM_HIER_FAKTOR_PK
  ENABLE VALIDATE);


Insert into STAMM_HIER_FAKTOR
   (KOMPONENTE, FAKTOR)
 Values
   ('730014', 1);
Insert into STAMM_HIER_FAKTOR
   (KOMPONENTE, FAKTOR)
 Values
   ('809579', 2);
Insert into STAMM_HIER_FAKTOR
   (KOMPONENTE, FAKTOR)
 Values
   ('718750', 3);
Insert into STAMM_HIER_FAKTOR
   (KOMPONENTE, FAKTOR)
 Values
   ('12345', 4);
Insert into STAMM_HIER_FAKTOR
   (KOMPONENTE, FAKTOR)
 Values
   ('718749', 5);
COMMIT;
...
Рейтинг: 0 / 0
10.09.2017, 11:30
    #39518741
Нарастающий итог (агрегированные суммы) по иерархии с применением фактора
Привел иерархию в более упрощенный вид, тем что агрегировал последние элементы с предпоследними, т.к. фактор в последних элементах не учитывается:

Код: 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.
set linesize 1000
with hier#
as
(SELECT
       hier.material, hier.komponente, hier.path, sum(Measure) as measure,max(fak.faktor) faktor
FROM
(
            SELECT 
                    CASE CONNECT_BY_ISLEAF
                       WHEN 1 THEN  
                          prior material
                       ELSE material
                    END as material,
                   CASE CONNECT_BY_ISLEAF
                       WHEN 1 THEN  
                          prior KOMPONENTE
                       ELSE KOMPONENTE
                    END as komponente,
                   CASE CONNECT_BY_ISLEAF
                       WHEN 1 THEN 
                         prior cast(SYS_CONNECT_BY_PATH(komponente,'/') as varchar2(40)) 
                       ELSE cast(SYS_CONNECT_BY_PATH(komponente,'/') as varchar2(40)) 
                   END as path,
                   Measure
             from STAMM_HIER
                 START WITH MATERIAL is NULL
                 CONNECT BY NOCYCLE  PRIOR KOMPONENTE =  MATERIAL
) hier, STAMM_HIER_FAKTOR fak
where hier.komponente = fak.komponente (+)
group by hier.material, hier.komponente, hier.path
)
SELECT 
*
FROM hier# t1
order by 3



Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
MATERIAL     KOMPONENTE   PATH                                        MEASURE     FAKTOR
------------ ------------ ---------------------------------------- ---------- ----------
             12345        /12345                                           20          4
12345        718749       /12345/718749                                     2          5
718749       730014       /12345/718749/730014                              2          1
730014       809579       /12345/718749/730014/809579                      11          2
12345        718750       /12345/718750                                    11          3
718750       809579       /12345/718750/809579                             11          2

6 rows selected.

Проблема в томе что, никак не могу получить сумму предыдущих элементов по иерархии.

P.S. В настоящей задачи дополнительно к выражению (measure * faktor) прибавляются еще пару констант, поэтому вынос faktor "за скобку" не будет работать.

Результат в Ехcel:
...
Рейтинг: 0 / 0
10.09.2017, 15:37
    #39518788
SY
SY
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Нарастающий итог (агрегированные суммы) по иерархии с применением фактора
Что-то типа:

Код: 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.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
with h as (
           select  rownum as rn,
                   material,
                   t1.komponente,
                   connect_by_root t1.komponente root,
                   cast(sys_connect_by_path(t1.komponente,'/') || '/' as varchar2(40)) as path,
                   cast(lpad(' ',3*(level-1)) || t1.komponente as varchar2(20)) as komponente_hier,
                   measure,
                   nvl(faktor,1) faktor,
                   connect_by_isleaf isleaf,
                   level as level_
             from  stamm_hier t1,
                   stamm_hier_faktor t2
             where t2.komponente(+) = t1.komponente
             start with material is null
             connect by nocycle prior t1.komponente =  material
          )
select  rn,
        material,
        komponente,
        root,
        path,
        komponente_hier,
        measure,
        faktor,
        faktor_running_sum,
        isleaf,
        level_
  from  h
  model
    dimension by(
                 path,
                 level_
                )
    measures(
             rn,
             material,
             komponente,
             root,
             komponente_hier,
             measure,
             faktor,
             isleaf,
             0 faktor_running_sum
            )
    rules
      (
       faktor_running_sum[any,any] order by path desc = faktor[cv(),cv()] *
                                                        (
                                                         measure[cv(),cv()] +
                                                         sum(faktor_running_sum)[instr(path,cv()) = 1,level_ - cv() in (0,1)]
                                                        )
      )
/

 RN MATERIAL KOMPONENTE ROOT  PATH                                KOMPONENTE_HIER      MEASURE     FAKTOR FAKTOR_RUNNING_SUM ISLEAF LEVEL_
--- -------- ---------- ----- ----------------------------------- -------------------- ------- ---------- ------------------ ------ ------
  1          12345      12345 /12345/                             12345                     20          4                996      0      1
  2 12345    718749     12345 /12345/718749/                         718749                  2          5                130      0      2
  3 718749   730014     12345 /12345/718749/730014/                     730014               2          1                 24      0      3
  4 730014   809579     12345 /12345/718749/730014/809579/                 809579            5          2                 22      0      4
  5 809579   111111     12345 /12345/718749/730014/809579/111111/             111111         1          1                  1      1      5
  6 809579   222222     12345 /12345/718749/730014/809579/222222/             222222         1          1                  1      1      5
  7 809579   798808     12345 /12345/718749/730014/809579/798808/             798808         4          1                  4      1      5
  8 12345    718750     12345 /12345/718750/                         718750                  9          3                 99      0      2
  9 718750   111111     12345 /12345/718750/111111/                     111111               1          1                  1      1      3
 10 718750   222222     12345 /12345/718750/222222/                     222222               1          1                  1      1      3
 11 718750   809579     12345 /12345/718750/809579/                     809579               5          2                 22      0      3
 12 809579   111111     12345 /12345/718750/809579/111111/                 111111            1          1                  1      1      4
 13 809579   222222     12345 /12345/718750/809579/222222/                 222222            1          1                  1      1      4
 14 809579   798808     12345 /12345/718750/809579/798808/                 798808            4          1                  4      1      4

14 rows selected.

SQL> 



SY.
...
Рейтинг: 0 / 0
10.09.2017, 15:45
    #39518790
Нарастающий итог (агрегированные суммы) по иерархии с применением фактора
SY,

спасибо!!! Круто!!!
Сейчас буду разбираться.
...
Рейтинг: 0 / 0
10.09.2017, 20:28
    #39518876
dbms_photoshop
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Нарастающий итог (агрегированные суммы) по иерархии с применением фактора
Hans Christian Andersen,

Дедовский метод со вложенной деревяшкой.

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
select h1.*,
       (select sum(xmlcast(xmlquery((measure || sys_connect_by_path(faktor, '*')) returning content) as int))
          from hier# h0
         start with h0.path = h1.path
        connect by prior komponente = material) x
  from hier# h1
 order by 3;

MATERIAL     KOMPONENTE   PATH                              MEASURE     FAKTOR          X
------------ ------------ ------------------------------ ---------- ---------- ----------
             12345        /12345                                 20          4        996
12345        718749       /12345/718749                           2          5        130
718749       730014       /12345/718749/730014                    2          1         24
730014       809579       /12345/718749/730014/809579            11          2         22
12345        718750       /12345/718750                          11          3         99
718750       809579       /12345/718750/809579                   11          2         22

6 rows selected.



Еще можно self join по like если вычислить path с произведением факторов.
...
Рейтинг: 0 / 0
11.09.2017, 01:39
    #39518938
Нарастающий итог (агрегированные суммы) по иерархии с применением фактора
Спасибо Вам dbms_photoshop,
но я использую решение SY, т.к. вместо faktor нужно применять формулу.
Для опыта, ваше решение очень полезно!

P.S. Спасибо SY за решение. Я протестировал с маленьким количеством данных - все работает.
Буду пробовать запрос с большим количеством элементов.
...
Рейтинг: 0 / 0
11.09.2017, 14:07
    #39519175
SY
SY
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Нарастающий итог (агрегированные суммы) по иерархии с применением фактора
dbms_photoshopДедовский метод со вложенной деревяшкой.


Не слишком эффективно, так-как число строимых иерархий равно числу строк таблицы, когда нам нужна одна иерархия и рекурсивное вычисление вверх от листа. MODEL можно заменить на recursive subquery factoring.

SY.
...
Рейтинг: 0 / 0
11.09.2017, 15:56
    #39519284
dbms_photoshop
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Нарастающий итог (агрегированные суммы) по иерархии с применением фактора
SYНе слишком эффективноСпору нет, было написано просто для полноты картины.
Модель здесь лучше, потому что учитывает уже посчитанное.
Но если мы гонимся за перфомансом, то думаю PL/SQL решение уделает модель на порядки.
SYMODEL можно заменить на recursive subquery factoring.С обходом снизу вверх?

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

Код: 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.
with h as
 (select h1.*,
         decode((select count(*) from hier# h2 where h2.material = h1.komponente), 0, 1, 0) leaf,
         regexp_count(path, '/') orig_lvl,
         max(regexp_count(path, '/')) over() depth
    from hier# h1),
rec(lvl, material, komponente, path, measure, faktor, x, rn) as
 (select depth,
         material,
         komponente,
         path,
         measure,
         faktor,
         measure * faktor,
         1
    from h
   where orig_lvl = depth
  union all
  select r.lvl - 1,
         h.material,
         h.komponente,
         h.path,
         h.measure,
         h.faktor,
         (h.measure + sum(decode(h.komponente, r.material, r.x, 0))
          over(partition by h.path)) * h.faktor,
         row_number() over(partition by h.path order by null)
    from h
    join rec r
      on (h.komponente = r.material and r.rn = 1)
      or (h.leaf = 1 and h.orig_lvl = r.lvl - 1))
select * from rec where rn = 1 order by path;

       LVL MATERIAL     KOMPONENTE   PATH                              MEASURE     FAKTOR          X      RN
---------- ------------ ------------ ------------------------------ ---------- ---------- ---------- ----------
         1              12345        /12345                                 20          4        996          1
         2 12345        718749       /12345/718749                           2          5        130          1
         3 718749       730014       /12345/718749/730014                    2          1         24          1
         4 730014       809579       /12345/718749/730014/809579            11          2         22          1
         2 12345        718750       /12345/718750                          11          3         99          1
         3 718750       809579       /12345/718750/809579                   11          2         22          1

6 rows selected.



Или есть вариант попроще?
...
Рейтинг: 0 / 0
11.09.2017, 17:22
    #39519369
SY
SY
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Нарастающий итог (агрегированные суммы) по иерархии с применением фактора
dbms_photoshopС обходом снизу вверх?


Да нет, я же сказал "MODEL можно заменить на recursive subquery factoring", а иерархию всерху-вниз кончно не трогаем.

SY.
...
Рейтинг: 0 / 0
11.09.2017, 17:43
    #39519391
dbms_photoshop
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Нарастающий итог (агрегированные суммы) по иерархии с применением фактора
SYdbms_photoshopС обходом снизу вверх?


Да нет, я же сказал "MODEL можно заменить на recursive subquery factoring", а иерархию всерху-вниз кончно не трогаем.

SY.Если присмотреться, я использовал hier#, которую ввел автор как раз как иерархию от корня.
Потом на основании ёё идет агрегация к корню с помощью rec with.
Все это требует хитрого соединения в рекурсивном члене по OR и пару других трюков.

Вопрос был, есть ли идеи для более простого решения. Выражение "можно заменить" ну никак не проясняет подход.
...
Рейтинг: 0 / 0
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Нарастающий итог (агрегированные суммы) по иерархии с применением фактора / 10 сообщений из 10, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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