powered by simpleCommunicator - 2.0.30     © 2024 Programmizd 02
Map
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Плоскую таблицу преобразовать в Иерархическую
17 сообщений из 42, страница 2 из 2
Плоскую таблицу преобразовать в Иерархическую
    #40121752
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SergiiW
Еще раз спасибо, именно то что нужно было бы, если бы не не постоянные ID. Но идея великолепная!


Код в моем примере дает постоянные ID и не требует unpivot, аналитику, итд.

SY.
...
Рейтинг: 0 / 0
Плоскую таблицу преобразовать в Иерархическую
    #40121767
SergiiW
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SY
Код в моем примере дает постоянные ID и не требует unpivot, аналитику, итд.
Спасибо, я, пока, разбираюсь в Вашим кодом, моих познаний мало, чтобы его быстро осмыслить.
Но у меня есть сомнения в по поводу постоянности ID. Плоская таблица каждый день создается наново. Я там ничего хранить не могу, я только ее читаю как есть.
Насколько я понимаю, обеспечить постоянство ID можно только сравнивая плоскую таблицу с иерархической.
...
Рейтинг: 0 / 0
Плоскую таблицу преобразовать в Иерархическую
    #40121781
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Sayan Malakshinov
При большом объёме обычно как раз оптимизируют путем создания плоских мвьюх по иерархическим таблицам
Кстати, а возможен refresh complete on commit для таких мвьюх?
И меня не получалось.
...
Рейтинг: 0 / 0
Плоскую таблицу преобразовать в Иерархическую
    #40121809
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SergiiW

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


Т.е. плоская таблица каждый день создается наново a иерархическая нет? Если да, то я бы вместо HIERARCHY_ID, VERSION как в моем примере добавил бы HIERARCHY_HASH в обе таблицы и заполнял это поле через DBMS_CRYPTO.HASH хешируя NAME1 || '|' || NAME || '|' || NAME3... ( если | может встречаться в NAME то замени | на символ который встречаться не может). Таким образом ты получишь постоянные ID для той-же самой иерархии.

SY.
...
Рейтинг: 0 / 0
Плоскую таблицу преобразовать в Иерархическую
    #40121812
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
Elic
Sayan Malakshinov
При большом объёме обычно как раз оптимизируют путем создания плоских мвьюх по иерархическим таблицам
Кстати, а возможен refresh complete on commit для таких мвьюх?
И меня не получалось.
к сожалению, нет, тк on commit требует выполнения условий для fast refreshable, а connect-by в этом списке ограничений
...
Рейтинг: 0 / 0
Плоскую таблицу преобразовать в Иерархическую
    #40121817
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Sayan Malakshinov
к сожалению, нет, тк on commit требует выполнения условий для fast refreshable, а connect-by в этом списке ограничений


Почему-же? Простое в лоб MV дает и fast refresh и on commit. Все что нам нужно знать это max возможную глубину иерархии. Например 4 для таблицы EMP:

Код: 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.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
CREATE MATERIALIZED VIEW LOG
  ON EMP
  WITH PRIMARY KEY,
       ROWID,
       SEQUENCE(
                ENAME,
                JOB,
                MGR,
                HIREDATE,
                SAL,
                COMM,
                DEPTNO
               )
       INCLUDING NEW VALUES
/
CREATE MATERIALIZED VIEW EMP_MV
  REFRESH FAST
  ON COMMIT
  AS
    SELECT  L1.EMPNO EMPNO_L1,
            L2.EMPNO EMPNO_L2,
            L3.EMPNO EMPNO_L3,
            L4.EMPNO EMPNO_L4,
            L1.ROWID L1_ROWID,
            L2.ROWID L2_ROWID,
            L3.ROWID L3_ROWID,
            L4.ROWID L4_ROWID
      FROM  EMP L1,
            EMP L2,
            EMP L3,
            EMP L4
      WHERE L1.MGR IS NULL
        AND L2.MGR(+) = L1.EMPNO
        AND L3.MGR(+) = L2.EMPNO
        AND L4.MGR(+) = L3.EMPNO
/

Materialized view created.

SQL> SELECT  EMPNO_L1,
  2          EMPNO_L2,
  3          EMPNO_L3,
  4          EMPNO_L4
  5    FROM  EMP_MV
  6  /

  EMPNO_L1   EMPNO_L2   EMPNO_L3   EMPNO_L4
---------- ---------- ---------- ----------
      7839       7566       7902       7369
      7839       7566       7788       7876
      7839       7698       7521
      7839       7698       7499
      7839       7698       7900
      7839       7782       7934
      7839       7698       7654
      7839       7698       7844

8 rows selected.

SQL> UPDATE EMP
  2     SET EMPNO = 8888
  3   WHERE EMPNO = 7698
  4  /

1 row updated.

SQL> UPDATE EMP
  2     SET MGR = 8888
  3   WHERE MGR = 7698
  4  /

5 rows updated.

SQL> INSERT
  2    INTO EMP
  3    VALUES(9999,'BAKER','CLERK',7844,TRUNC(SYSDATE),1234,NULL,30)
  4  /

1 row created.

SQL> COMMIT
  2  /

Commit complete.

SQL> SELECT  EMPNO_L1,
  2          EMPNO_L2,
  3          EMPNO_L3,
  4          EMPNO_L4
  5    FROM  EMP_MV
  6  /

  EMPNO_L1   EMPNO_L2   EMPNO_L3   EMPNO_L4
---------- ---------- ---------- ----------
      7839       7566       7902       7369
      7839       7566       7788       7876
      7839       7782       7934
      7839       8888       7844       9999
      7839       8888       7521
      7839       8888       7499
      7839       8888       7900
      7839       8888       7654

8 rows selected.

SQL> UPDATE EMP
  2     SET EMPNO = 7698
  3   WHERE EMPNO = 8888
  4  /

1 row updated.

SQL> UPDATE EMP
  2     SET MGR = 7698
  3   WHERE MGR = 8888
  4  /

5 rows updated.

SQL> DELETE EMP
  2   WHERE EMPNO = 9999
  3  /

1 row deleted.

SQL> COMMIT
  2  /

Commit complete.

SQL> SELECT  EMPNO_L1,
  2          EMPNO_L2,
  3          EMPNO_L3,
  4          EMPNO_L4
  5    FROM  EMP_MV
  6  /

  EMPNO_L1   EMPNO_L2   EMPNO_L3   EMPNO_L4
---------- ---------- ---------- ----------
      7839       7566       7902       7369
      7839       7566       7788       7876
      7839       7782       7934
      7839       7698       7521
      7839       7698       7499
      7839       7698       7900
      7839       7698       7654
      7839       7698       7844

8 rows selected.

SQL>



Конечно self-join таблицы max возможная глубина иерархия раз не шашечки, но едет.

SY.
...
Рейтинг: 0 / 0
Плоскую таблицу преобразовать в Иерархическую
    #40121832
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SY
Все что нам нужно знать это max возможную глубину иерархии.
Ну да, "всего лишь".
Более того, connect by размножает строки, например для получения прямых связей:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
select
    connect_by_root id as id
  , id as any_parent_id 
  from tbl
  where level >= 2
  connect by id = prior parent_id
;

SY
Конечно self-join таблицы max возможная глубина иерархия раз не шашечки, но едет.
self-join-ом можно сэмулировать ограниченное подмножество иерархических запросов.
...
Рейтинг: 0 / 0
Плоскую таблицу преобразовать в Иерархическую
    #40121848
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
SY
Почему-же? Простое в лоб MV дает и fast refresh и on commit. Все что нам нужно знать это max возможную глубину иерархии. Например 4 для таблицы EMP:
ну, вообще, я говорил именно про рекурсивные запросы (что connect-by, что recursive subq factoring в списке ограничений). Да, конечно, способ с разворачиванием в джойны хорошо распространен, но ты сделал немного не так: в твоем запросе фактически идет схлопывание, а-ля connect_by_isleaf=1, что обычно добавляет сложности и далеко не везде зайдет.
Обычно делается что-то типа такого:
Код: 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.
--drop materialized view mv_plain_hierarchy;
--drop table t_hierarchy purge;
create table t_hierarchy(
   id        int primary key
  ,parent_id int
  ,name      varchar2(10)
  ,constraint fk_parent foreign key (parent_id) references t_hierarchy(id)
);
create materialized view log on t_hierarchy 
  with primary key,rowid,
       sequence(parent_id,name)
  including new values;
create materialized view mv_plain_hierarchy 
refresh fast on commit
as
select
   h0.id
  ,decode(null,h1.id,1,h2.id,2,h3.id,3,4) lvl
  ,coalesce(h3.id,h2.id,h1.id,h0.id) lvl_1
  ,decode(null, h1.id,to_number(null), h2.id,h0.id, h3.id,h1.id, h2.id) lvl_2
  ,decode(null, h1.id,to_number(null), h2.id,null,  h3.id,h0.id, h1.id) lvl_3
  ,decode(null, h1.id,to_number(null), h2.id,null,  h3.id,null , h0.id) lvl_4
  ,ck.id as ck
  ,h0.rowid h0_rid,h1.rowid h1_rid,h2.rowid h2_rid,h3.rowid h3_rid,ck.rowid ck_rid
from t_hierarchy h0
    ,t_hierarchy h1 
    ,t_hierarchy h2 
    ,t_hierarchy h3 
    ,t_hierarchy ck
where
    h1.id(+)=h0.parent_id
and h2.id(+)=h1.parent_id
and h3.id(+)=h2.parent_id
and ck.id(+)=h3.parent_id
;
create index mv_ix_1 on mv_plain_hierarchy(id);
create index mv_ix_2 on mv_plain_hierarchy(lvl_1);
alter table mv_plain_hierarchy add constraint mv_chk_level check (ck is null);


Что это дает:
  • кол-во строк у обоих таблиц одинаково (легкая валидация, простые джойны при необходимости);
  • каждый элемент изначальной таблицы имеет свою запись в развернутой, со своей доп.инфой типа уровня иерархии элемента и прочего, при необходимости;
  • констрейнт дает возможность контролировать глубину иерархии, чтобы не случилось внезапного расхождения данных.
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
begin
  insert into t_hierarchy values (1   ,null,'name_1');
  insert into t_hierarchy values (10  ,1   ,'name_10');
  insert into t_hierarchy values (100 ,10  ,'name_100');
  insert into t_hierarchy values (11  ,1   ,'name_11');
  insert into t_hierarchy values (110 ,11  ,'name_110');
  insert into t_hierarchy values (2   ,null,'name_2');
  insert into t_hierarchy values (20  ,2   ,'name_20');
  insert into t_hierarchy values (200 ,20  ,'name_200');
  insert into t_hierarchy values (21  ,2   ,'name_21');
  insert into t_hierarchy values (210 ,21  ,'name_210');
  insert into t_hierarchy values (2100 ,210  ,'name_2100');
  commit;
end;
/


мы получим:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
SQL> select id,lvl,lvl_1,lvl_2,lvl_3,lvl_4 from mv_plain_hierarchy;

        ID        LVL      LVL_1      LVL_2      LVL_3      LVL_4
---------- ---------- ---------- ---------- ---------- ----------
         1          1          1
        10          2          1         10
       100          3          1         10        100
        11          2          1         11
       110          3          1         11        110
         2          1          2
        20          2          2         20
       200          3          2         20        200
        21          2          2         21
       210          3          2         21        210
      2100          4          2         21        210       2100

11 rows selected.


А при попытке вставить элемент более глубокого уровня получим ошибку:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
SQL> begin
  2    insert into t_hierarchy values (21000 ,2100  ,'fail');
  3    commit;
  4  end;
  5  /
begin
*
ERROR at line 1:
ORA-12008: error in materialized view or zonemap refresh path
ORA-02290: check constraint (XTENDER.MV_CHK_LEVEL) violated
ORA-06512: at line 3



Полный скрипт для тестов тут: https://gist.github.com/xtender/7d2449f3132624bf4b2819a4a4c01c87
...
Рейтинг: 0 / 0
Плоскую таблицу преобразовать в Иерархическую
    #40121884
SergiiW
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SY
Т.е. плоская таблица каждый день создается наново a иерархическая нет?
Да.
SY
DBMS_CRYPTO.HASH хешируя NAME1 || '|' || NAME || '|' || NAME3...

Думаю, это ничего не даст. Мне нужно не ID всей строки, а ID Name1, ID - Name2 (с учетом родителя), ...
...
Рейтинг: 0 / 0
Плоскую таблицу преобразовать в Иерархическую
    #40121889
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SergiiW
Мне нужно не ID всей строки, а ID Name1, ID - Name2 (с учетом родителя), ...


Вы б привели пример Вашей плоской таблицы,
напр для emp.ename, плоская таблица выглядит ...

зы
если "ID" символьное, не поможет

....
stax
...
Рейтинг: 0 / 0
Плоскую таблицу преобразовать в Иерархическую
    #40121892
SergiiW
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Stax
Вы б привели пример Вашей плоской таблицы,

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
SELECT 'VANIA' NAME1,
       'PETYA' NAME2,
       'SASHA' NAME3,
       'PASHA' NAME4,
       'VOVA'  NAME5,
       'VIKA'  NAME6
FROM  DUAL
UNION ALL
SELECT 'MISHA' NAME1,
       'MASHA' NAME2,
       'PASHA' NAME3,
       NULL    NAME4,
       'GOSHA' NAME5, -- Родитель NAME3 (PASHA)
       'KESHA' NAME6
 FROM  DUAL
...
Рейтинг: 0 / 0
Плоскую таблицу преобразовать в Иерархическую
    #40121906
SergiiW
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Еще раз спасибо всем за помощь!
Свою задачу с вашей помощью я решил.
Кратко:
1. Сделал View V_FH на основе запроса
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
SELECT 
  p.Name1, P.Name2, P.Name3, P.Name4, P.Name5, P.Name6,
  a1.PID PID1, a1.ID ID1,
  a2.PID PID2, a2.ID ID2,
  a3.PID PID3, a3.ID ID3,
  a4.PID PID4, a4.ID ID4,
  a5.PID PID5, a5.ID ID5,
  a6.PID PID6, a6.ID ID6
from FLAT p 
  LEFT JOIN HIERARCHY A1 ON A1.PID IS null AND A1.NAME = P.Name1
  LEFT JOIN HIERARCHY A2 ON A2.PID = A1.ID AND A2.NAME = P.Name2
  LEFT JOIN HIERARCHY A3 ON A3.PID = A2.ID AND A3.NAME = P.Name3
  LEFT JOIN HIERARCHY A4 ON A4.PID = A3.ID AND A4.NAME = p.Name4
  LEFT JOIN HIERARCHY A5 ON A5.PID = NVL(A4.ID, A3.ID) AND A5.NAME = p.Name5
  LEFT JOIN HIERARCHY A6 ON A6.PID = A5.ID AND A6.NAME = p.Name6


2. Удаление через временную таблицу
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
INSERT INTO TMP (ID)
SELECT DISTINCT ID1 FROM V_FH UNION ALL
SELECT DISTINCT ID2 FROM V_FH UNION ALL
SELECT DISTINCT ID3 FROM V_FH UNION ALL
SELECT DISTINCT ID4 FROM V_FH UNION ALL
SELECT DISTINCT ID5 FROM V_FH UNION ALL
SELECT DISTINCT ID6 FROM V_FH;
DELETE FROM HIERARCHY H WHERE NOT EXISTS(SELECT 1 FROM TMP t WHERE T.ID = H.ID);


3. Обновление для каждого уровня отдельно
3.1
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
INSERT INTO HIERARCHY (id, NAME, PID)
SELECT
  i.i + ROWNUM ID, Name, PID
FROM (SELECT NVL(MAX(ID), 0) i FROM HIERARCHY) i, 
(SELECT
  Name1 Name, PID1 PID
from V_FH
WHERE ID1 IS NULL
GROUP BY Name1, PID1);


3.2
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
INSERT INTO HIERARCHY (id, NAME, PID)
SELECT
  i.i + ROWNUM ID, Name, PID
FROM (SELECT NVL(MAX(ID), 0) i FROM HIERARCHY) i, 
(SELECT
  Name2 Name, PID2 PID
from V_FH
WHERE ID1 IS NOT NULL AND ID2 IS NULL
GROUP BY Name2, PID2);


3.3 ...

Написал пост и понял, что PID в View не нужен. Можно без этого поля обойтись.
...
Рейтинг: 0 / 0
Плоскую таблицу преобразовать в Иерархическую
    #40121940
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SergiiW,

Создаем таблицы:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
DROP TABLE HIERARCHICAL PURGE
/
DROP TABLE FLAT_HIERARCHY PURGE
/
CREATE TABLE FLAT_HIERARCHY(
                            NAME1      VARCHAR2(10),
                            NAME2      VARCHAR2(10),
                            NAME3      VARCHAR2(10),
                            NAME4      VARCHAR2(10),
                            NAME5      VARCHAR2(10),
                            NAME6      VARCHAR2(10)
                           )
/
CREATE TABLE HIERARCHICAL(
                          HIER_HASH  RAW(2000),
                          ID         NUMBER,
                          PID        NUMBER,
                          NAME       VARCHAR2(10)
                         )
/



Заполняем плоскую:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
INSERT
  INTO FLAT_HIERARCHY
     SELECT  'VANIA' NAME1,
             'PETYA' NAME2,
             'SASHA' NAME3,
             'PASHA' NAME4,
             'VOVA'  NAME5,
             'VIKA'  NAME6
       FROM  DUAL
    UNION ALL
     SELECT  'MISHA' NAME1,
             'MASHA' NAME2,
             'PASHA' NAME3,
             NULL    NAME4,
            'GOSHA' NAME5, -- Родитель NAME3 (PASHA)
            'KESHA' NAME6
      FROM  DUAL
/
COMMIT
/



В иерархию добавляем только новое:

Код: 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.
MERGE
  INTO HIERARCHICAL T
  USING (
         WITH F AS (
                    SELECT  DBMS_CRYPTO.HASH(TO_CLOB(NAME1) || '|' || NAME2 || '|' || NAME3 || '|' || NAME4 || '|' || NAME5 || '|' || NAME6,3) HIER_HASH,
                            ID,
                            CASE ID
                              WHEN 1 THEN NAME1
                              WHEN 2 THEN NAME2
                              WHEN 3 THEN NAME3
                              WHEN 4 THEN NAME4
                              WHEN 5 THEN NAME5
                              ELSE NAME6
                            END NAME
                      FROM  FLAT_HIERARCHY,
                            LATERAL(
                                    SELECT  LEVEL ID
                                      FROM  DUAL
                                      CONNECT BY LEVEL <= 6
                                   )
                   )
         SELECT  HIER_HASH,
                 ID,
                 LAG(ID) OVER(PARTITION BY HIER_HASH ORDER BY ID) PID,
                 NAME
           FROM  F
           WHERE NAME IS NOT NULL
        ) S
  ON (
      T.HIER_HASH = S.HIER_HASH
     )
  WHEN NOT MATCHED
    THEN
      INSERT
        VALUES(
               S.HIER_HASH,
               S.ID,
               S.PID,
               S.NAME
              )
/
COMMIT
/



Имеем:

Код: 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.
COLUMN ID_INDENTED FORMAT A12
SELECT  RPAD(' ',2 * (LEVEL - 1)) || ID ID_INDENTED,
        PID,
        NAME
  FROM  HIERARCHICAL
  START WITH PID IS NULL
  CONNECT BY HIER_HASH = PRIOR HIER_HASH
         AND PID = PRIOR ID
/

ID_INDENTED         PID NAME
------------ ---------- ----------
1                       VANIA
  2                   1 PETYA
    3                 2 SASHA
      4               3 PASHA
        5             4 VOVA
          6           5 VIKA
1                       MISHA
  2                   1 MASHA
    3                 2 PASHA
      5               3 GOSHA -- Родитель ID=3 (PASHA)
        6             5 KESHA

11 rows selected.

SQL>



Удаляем все из плоской и заполняем тем-же плюс новая иерархия:

Код: 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.
TRUNCATE TABLE FLAT_HIERARCHY
/
INSERT
  INTO FLAT_HIERARCHY
     SELECT  'VANIA' NAME1,
             'PETYA' NAME2,
             'SASHA' NAME3,
             'PASHA' NAME4,
             'VOVA'  NAME5,
             'VIKA'  NAME6
       FROM  DUAL
    UNION ALL
     SELECT  'MISHA' NAME1,
             'MASHA' NAME2,
             'PASHA' NAME3,
             NULL    NAME4,
            'GOSHA' NAME5, -- Родитель NAME3 (PASHA)
            'KESHA' NAME6
      FROM  DUAL
    UNION ALL
     SELECT  'DAVID'   NAME1,
             'MICHAEL' NAME2,
             'RYAN'    NAME3,
             'KEVIN'   NAME4,
             NULL      NAME5,
             NULL      NAME6
      FROM  DUAL
/
COMMIT
/



Выполняем NERGE:

Код: 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.
MERGE
  INTO HIERARCHICAL T
  USING (
         WITH F AS (
                    SELECT  DBMS_CRYPTO.HASH(TO_CLOB(NAME1) || '|' || NAME2 || '|' || NAME3 || '|' || NAME4 || '|' || NAME5 || '|' || NAME6,3) HIER_HASH,
                            ID,
                            CASE ID
                              WHEN 1 THEN NAME1
                              WHEN 2 THEN NAME2
                              WHEN 3 THEN NAME3
                              WHEN 4 THEN NAME4
                              WHEN 5 THEN NAME5
                              ELSE NAME6
                            END NAME
                      FROM  FLAT_HIERARCHY,
                            LATERAL(
                                    SELECT  LEVEL ID
                                      FROM  DUAL
                                      CONNECT BY LEVEL <= 6
                                   )
                   )
         SELECT  HIER_HASH,
                 ID,
                 LAG(ID) OVER(PARTITION BY HIER_HASH ORDER BY ID) PID,
                 NAME
           FROM  F
           WHERE NAME IS NOT NULL
        ) S
  ON (
      T.HIER_HASH = S.HIER_HASH
     )
  WHEN NOT MATCHED
    THEN
      INSERT
        VALUES(
               S.HIER_HASH,
               S.ID,
               S.PID,
               S.NAME
              )
/

4 rows merged. -- добавилась только новая иерархия

SQL> COMMIT
  2  /

Commit complete.

SQL>



Имеем:

Код: 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.
SELECT  RPAD(' ',2 * (LEVEL - 1)) || ID ID_INDENTED,
        PID,
        NAME
  FROM  HIERARCHICAL
  START WITH PID IS NULL
  CONNECT BY HIER_HASH = PRIOR HIER_HASH
         AND PID = PRIOR ID
/

ID_INDENTED         PID NAME
------------ ---------- ----------
1                       VANIA
  2                   1 PETYA
    3                 2 SASHA
      4               3 PASHA
        5             4 VOVA
          6           5 VIKA
1                       MISHA
  2                   1 MASHA
    3                 2 PASHA
      5               3 GOSHA
        6             5 KESHA
1                       DAVID
  2                   1 MICHAEL
    3                 2 RYAN
      4               3 KEVIN

15 rows selected.

SQL>



SY.
...
Рейтинг: 0 / 0
Плоскую таблицу преобразовать в Иерархическую
    #40121982
SergiiW
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SY,

Спасибо! Интересное решение, но есть несколько но.
1. Оно более сложно для восприятия, понимания, по крайней мере для меня, и, соответственно, мне или другим будет сложнее его поддерживать. Даже несмотря на то, что оно может быть более универсальное и содержать меньше кода. Возможно, это субъективное мнение потому, что не я создавал этот код.
2. Отсутствует удаление записей, которых нет в плоской таблице.
3. ID не уникальное. То есть, выборки по ID или по PID будут проблематичны.
...
Рейтинг: 0 / 0
Плоскую таблицу преобразовать в Иерархическую
    #40122011
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SergiiW
SY,

Спасибо! Интересное решение, но есть несколько но.
1. Оно более сложно для восприятия, понимания, по крайней мере для меня, и, соответственно, мне или другим будет сложнее его поддерживать. Даже несмотря на то, что оно может быть более универсальное и содержать меньше кода. Возможно, это субъективное мнение потому, что не я создавал этот код.
2. Отсутствует удаление записей, которых нет в плоской таблице.
3. ID не уникальное. То есть, выборки по ID или по PID будут проблематичны.


1. Все что используется в решении это хеш имен для проверки есть ли в HIERARCHICAL такая иерархия и самый обыкновенный MERGE так-что даже если у тебя с этим сложности то другим не будет сложнее его поддерживать разве-что они тоже entry level.
2. Ну так добавь это в MERGE или просто выполни

Код: plsql
1.
2.
3.
4.
5.
6.
DELETE HIERARCHICAL
 WHERE HIER_HASH NOT IN (
                         SELECT  DBMS_CRYPTO.HASH(TO_CLOB(NAME1) || '|' || NAME2 || '|' || NAME3 || '|' || NAME4 || '|' || NAME5 || '|' || NAME6,3)
                           FROM  FLAT_HIERARCHY
                        )
/



3. Все ID/PID уникальные в пределах иерархии. Сколько бы раз мы бы ни создавали иерархию из той-же плоской 'MISHA', 'MASHA', 'PASHA', NULL, 'GOSHA','KESHA' всегда MISHA получит ID = 1 а GOSHA получит ID = 5. Кроме того ID/PID это artificial key и привязка к нему превращает их в natural keys. Зачем привязываться к ID/PID если у нас есть имена? Приведи пример (словами) что ищется в таблице HIERARCHICAL. Например, найти непосредственных родителей Васи во всех иерархиях.

SY.
...
Рейтинг: 0 / 0
Плоскую таблицу преобразовать в Иерархическую
    #40122029
SergiiW
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SY,


ORA-00904: "DBMS_CRYPTO"."HASH": invalid identifier
...
Рейтинг: 0 / 0
Плоскую таблицу преобразовать в Иерархическую
    #40122178
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SergiiW
SY,


ORA-00904: "DBMS_CRYPTO"."HASH": invalid identifier


Ну так попроси DBA дать тебе EXECUTE на DBMS_CRYPTO.

SY.
...
Рейтинг: 0 / 0
17 сообщений из 42, страница 2 из 2
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Плоскую таблицу преобразовать в Иерархическую
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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