Hierarchical Data - Storage and Queries
Submitted by dave on Thu, 09/13/2012 - 17:23
Storing Hierarchical Data
Bill Karwin - Models for Hierarchical Data
Hierarchical as relational
StackOverflow - Options for Hierarchical in RDBMS
StackOverflow - Store and navigate hierarchies
Implementing a Closure Table
Querying Hierarchical Data
START WITH...CONNECT BY documentation
AMIS Blog on Recursive Subquery Refactoring replacement for CONNECT BY
Detecting Cycles in Hierarchical Data
-- Simple 3 node tree with no cycle CREATE TABLE EMPLOYEE_CYCLE (ENAME VARCHAR2(20), MGR VARCHAR2(20)); insert into employee_cycle values ('EMP1',NULL); insert into employee_cycle values ('EMP2','EMP1'); insert into employee_cycle values ('EMP3','EMP2'); commit; -- This query shows entries involved in a cycle -- In this case it will return Zero Records SELECT SYS_CONNECT_BY_PATH (ENAME,'/') as EMPLOYEE_NAME, MGR, CONNECT_BY_ISCYCLE FROM employee_cycle WHERE CONNECT_BY_ISCYCLE = 1 CONNECT BY NOCYCLE PRIOR ENAME = MGR; -- Introduce a cycle into the tree, change EMP1's manager to EMP3 UPDATE employee_cycle set MGR='EMP3' WHERE ENAME='EMP1'; COMMIT; -- This query shows entries involved in a cycle -- In this case it will return 1 record for each entry involved in a cycle. SELECT SYS_CONNECT_BY_PATH (ENAME,'/') as EMPLOYEE_NAME, MGR, CONNECT_BY_ISCYCLE FROM employee_cycle WHERE CONNECT_BY_ISCYCLE = 1 CONNECT BY NOCYCLE PRIOR ENAME = MGR;
The 2nd query detects and returns all entries involved in a cycle:
EMPLOYEE_NAME MGR CONNECT_BY_ISCYCLE -------------------- ------- ------------------ /EMP2/EMP3/EMP1 EMP3 1 /EMP3/EMP1/EMP2 EMP1 1 /EMP1/EMP2/EMP3 EMP2 1
Cycle Detection with Recursive Subquery Refactoring
Closure Table Demo
-- Closure Table Demo -- I have seen lots of demos of closure table but most just hit the trivial -- cases - one tree stored in a table. Here is some exploration of -- multiple trees living in the same table. -- 1 10 -- / | \ / \ -- 2 3 6 11 12 -- | \ -- 4 7 -- | -- 5 CREATE TABLE REL (ANCESTOR NUMBER, DESCENDANT NUMBER); -- Data for Table 1 INSERT INTO REL VALUES (1,1); INSERT INTO REL VALUES (1,2); INSERT INTO REL VALUES (1,3); INSERT INTO REL VALUES (1,4); INSERT INTO REL VALUES (1,5); INSERT INTO REL VALUES (1,6); INSERT INTO REL VALUES (1,7); INSERT INTO REL VALUES (2,2); INSERT INTO REL VALUES (3,3); INSERT INTO REL VALUES (3,4); INSERT INTO REL VALUES (3,5); INSERT INTO REL VALUES (4,4); INSERT INTO REL VALUES (4,5); INSERT INTO REL VALUES (5,5); INSERT INTO REL VALUES (6,6); INSERT INTO REL VALUES (6,7); INSERT INTO REL VALUES (7,7); -- Data for Table 2 INSERT INTO REL VALUES (10,10); INSERT INTO REL VALUES (10,11); INSERT INTO REL VALUES (10,12); INSERT INTO REL VALUES (11,11); INSERT INTO REL VALUES (12,12); COMMIT; -- What are the root nodes? SELECT DISTINCT ANCESTOR FROM REL WHERE DESCENDANT NOT IN ( SELECT DESCENDANT FROM REL WHERE ANCESTOR<>DESCENDANT ); -- What are the children of 3 exclusive? SELECT DESCENDANT FROM REL WHERE ANCESTOR=3 AND DESCENDANT<>ANCESTOR; DESCENDANT ---------- 4 5 -- What are the parents of 3? SELECT ANCESTOR FROM REL WHERE DESCENDANT=3 AND DESCENDANT<>ANCESTOR; ANCESTOR -------- 1