[英]Oracle hierarchical sum (distance from leaf to root)
我想獲得分層查詢(Oracle 11gR2)的幫助。 我很難處理這些問題......
事實上,這是一個2合1問題(需要2種不同的方法)。
我正在尋找一種方法來獲得從所有個體記錄到根的距離(而不是相反)。 我的數據是樹狀結構:
CREATE TABLE MY_TREE
(ID_NAME VARCHAR2(1) PRIMARY KEY,
PARENT_ID VARCHAR2(1),
PARENT_DISTANCE NUMBER(2)
);
INSERT INTO MY_TREE (ID_NAME,PARENT_ID,PARENT_DISTANCE) VALUES('A',NULL,NULL);
INSERT INTO MY_TREE (ID_NAME,PARENT_ID,PARENT_DISTANCE) VALUES('B','A',1);
INSERT INTO MY_TREE (ID_NAME,PARENT_ID,PARENT_DISTANCE) VALUES('C','B',3);
INSERT INTO MY_TREE (ID_NAME,PARENT_ID,PARENT_DISTANCE) VALUES('D','B',5);
INSERT INTO MY_TREE (ID_NAME,PARENT_ID,PARENT_DISTANCE) VALUES('E','C',7);
INSERT INTO MY_TREE (ID_NAME,PARENT_ID,PARENT_DISTANCE) VALUES('F','D',11);
INSERT INTO MY_TREE (ID_NAME,PARENT_ID,PARENT_DISTANCE) VALUES('G','D',13);
從層次上看,我的數據看起來像這樣(但我有多個獨立的根和更多級別):
在第一個approch中,我正在尋找一個可以給我這個結果的查詢:
LEVEL ROOT NODE ID_NAME ROOT_DISTANCE
----- ---- ---- ------- -------------
1 A null A null
2 A null B 1
3 A B C 4
4 A B E 11
3 A B D 6
4 A D F 17
4 A D G 19
在這個結果中,
在這個approch中,我將始終指定最多2個根。
第二個approch必須是一個PL / SQL腳本,它將執行相同的計算(ROOT_DISTANCE),但是以迭代的方式,並將結果寫入新表。 我想一次運行這個腳本,所以將處理所有的根(~1000)。
這是我看到腳本的方式:
“性能視角”需要此腳本,因此如果已經計算了一個元素(例如:由另一個葉子計算的分割節點),我們需要停止計算並傳遞給下一個葉子,因為我們已經知道了結果從那里到根。 例如,如果系統計算ECBA,然后計算FDBA,則不應再次計算BA部分,因為它是在第一次傳遞中完成的。
你可以解決其中一個或兩個問題,但我需要這兩個問題的靈感。
謝謝!
試試這個:
WITH brumba(le_vel,root,node,id_name,root_distance) AS (
SELECT 1 as le_vel, id_name as root, null as node, id_name, to_number(null) as root_distance
FROM MY_TREE WHERE parent_id IS NULL
UNION ALL
SELECT b.le_vel + 1, b.root,
CASE WHEN 1 < (
SELECT count(*) FROM MY_TREE t1 WHERE t1.parent_id = t.parent_id
)
THEN t.parent_id ELSE b.node
END,
t.id_name, coalesce(b.root_distance,0)+t.parent_distance
FROM MY_TREE t
JOIN brumba b ON b.id_name = t.parent_id
)
SELECT * FROM brumba
演示: https : //dbfiddle.uk/?rbms = aracle_11.2&tele = d5c231055e989c3cbcd763f4b3d3033f
使用PL / SQL不需要“第二個approch” - 上面的SQL將一次計算所有根節點(在parent_id
列中為null)的結果。
只需在上面的查詢中添加INSERT INTO tablename(col1,col2, ... colN) ...
或CREATE TABLE name AS ...
的前綴。
上面的演示包含后一個選項CREATE TABLE xxx AS query
的示例
這是一個選項,顯示如何獲得問題的第一部分:
SQL> with temp as
2 (select level lvl,
3 ltrim(sys_connect_by_path(id_name, ','), ',') path
4 from my_tree
5 start with parent_id is null
6 connect by prior id_name = parent_id
7 ),
8 inter as
9 (select t.lvl,
10 t.path,
11 regexp_substr(t.path, '[^,]+', 1, column_value) col
12 from temp t,
13 table(cast(multiset(select level from dual
14 connect by level <= regexp_count(path, ',') + 1
15 ) as sys.odcinumberlist ))
16 )
17 select i.lvl,
18 i.path,
19 sum(m.parent_distance) dis
20 from inter i join my_tree m on m.id_name = i.col
21 group by i.lvl, i.path
22 order by i.path;
LVL PATH DIS
---- ---------- ----------
1 A
2 A,B 1
3 A,B,C 4
4 A,B,C,E 11
3 A,B,D 6
4 A,B,D,F 17
4 A,B,D,G 19
7 rows selected.
SQL>
以下是使用分層( connect by
)查詢解決此問題的方法。
在大多數分層問題中,分層查詢將比遞歸查詢更快( with
子句的遞歸)。 然而,你的問題不是純粹的層次-你需要計算到根的距離,而不像遞歸with
,你不能在單次使用層次查詢。 所以聽到你的消息會很有趣! - 這些方法之間是否存在任何顯着的性能差異。 對於它的價值,在您提供的非常小的數據樣本上,優化器使用connect by
估計成本為5,而遞歸解決方案則為48; 這是否意味着在現實生活中你會發現什么,希望你也會告訴我們。
在分層查詢中,我標記了有兩個或更多子節點的父節點(我為此使用了分析函數,以避免連接)。 然后我構建了層次結構,並在最后一步中聚合以獲得所需的位。 在遞歸解決方案中,這應該為您提供所需的一切 - 對於所有根和所有節點 - 在單個SQL查詢中; 不需要PL / SQL代碼。
with
branching (id_name, parent_id, parent_distance, b) as (
select id_name, parent_id, parent_distance,
case when count(*) over (partition by parent_id) > 1 then 'y' end
from my_tree
)
, hierarchy (lvl, leaf, id_name, parent_id, parent_distance, b) as (
select level, connect_by_root id_name, id_name, parent_id, parent_distance, b
from branching
connect by id_name = prior parent_id
)
select max(lvl) as lvl,
min(id_name) keep (dense_rank last order by lvl) as root,
leaf as id_name,
min(decode(b, 'y', parent_id))
keep (dense_rank first order by decode(b, 'y', lvl)) as node,
sum(parent_distance) as root_distance
from hierarchy
group by leaf;
LVL ROOT ID_NAME NODE ROOT_DISTANCE
--- ------- ------- ------- -------------
1 A A
2 A B 1
3 A C B 4
3 A D B 6
4 A E B 11
4 A F D 17
4 A G D 19
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.