360 likes | 477 Views
Accessing Hierarchical Data in Oracle. Carol-Lee Erikson Tutch ctutch@gmail.com. Hierarchically Structured Data. Items at different levels are similar Arbitrary number of levels Examples Personnel Officer Manager Contributor Manufacturing Product Assembly Part.
E N D
Accessing Hierarchical Data in Oracle Carol-Lee Erikson Tutch ctutch@gmail.com
Hierarchically Structured Data • Items at different levels are similar • Arbitrary number of levels • Examples • Personnel • Officer • Manager • Contributor • Manufacturing • Product • Assembly • Part
Representing a Hierarchy • Items have a Parent-Child relationship • Hierarchy can be visualized as a Tree • Item is called a Node • Connections btw nodes are Links • Node has 0 or 1 parent • Node w/o parent is a Root • Node has 0 to N children • Node w/o children is a Leaf
Hierarchy Tree 1 Level 1 2 9 15 Level 2 3 4 7 10 11 Level 3 5 6 8 12 13 Level 4 14 Level 5
Structure for Sample Data CREATETABLEemp( emp_idNUMBER(5)NOTNULL, emp_nameVARCHAR2(30)NOTNULL, mgr_emp_idNUMBER(5), dept_cdVARCHAR2(6), salNUMBER(9,2), hire_dtDATENOTNULL); CREATEUNIQUEINDEXemp_pkONemp(emp_id); ALTERTABLEempADDCONSTRAINTemp_pk PRIMARYKEY( emp_id)USINGINDEXemp_pk; CREATEINDEX emp_f1 ONemp(mgr_emp_idASC); ALTERTABLEempADDCONSTRAINT emp_f1 FOREIGNKEY(mgr_emp_id) REFERENCESemp(emp_id);
Sample Data SELECT * FROMemp ORDERBYemp_id;
Sample Data Graph 10 Barbara 16 George 33 Mary 24 John 12 Edward 11 John 14 Beth 17 Barby 13 Josh 15 Rich 21 Michelle 28 Sam 22 Tom 32 Jane 31 Robin
Employees & Supervisors SELECTe.emp_id,e.emp_name, m.emp_idASmgr_id,m.emp_nameASmgr_name FROMempeJOINempm ONe.mgr_emp_id=m.emp_id ORDERBYe.emp_id;
… Add Top-Level Supervisors SELECTe.emp_id,e.emp_name, m.emp_idASmgr_id,m.emp_nameASmgr_name FROMempeLEFTJOINempm ONe.mgr_emp_id=m.emp_id ORDERBYe.emp_id;
… Add Supervisor’s Supervisors SELECTe.emp_id,e.emp_name, m1.emp_id AS mgr_id1, m1.emp_name AS gr_name1, m2.emp_id AS mgr_id2, m2.emp_name AS mgr_name2 FROMempe LEFTJOINemp m1 ONe.mgr_emp_id= m1.emp_id LEFTJOINemp m2 ON m1.mgr_emp_id = m2.emp_id ORDERBYe.emp_id;
All Root Nodes SELECTe.emp_id,e.emp_name FROMempe WHEREe.mgr_emp_idISNULL;
All Leaf Nodes SELECTe.emp_id,e.emp_name FROMempe WHEREe.emp_idNOTIN (SELECTDISTINCTm.mgr_emp_id FROMempm WHEREm.mgr_emp_idISNOTNULL);
Oracle Extensions for Hierarchies • CONNECT BY clause • Allows linking w/n same range variable (table alias) • Occurs after WHERE clause • Executes before WHERE clause • PRIOR keyword • Indicates how to connect w/ last record retrieved • Can occur on either side of the join • Can be used multiple times • START WITH clause • Indicates record(s) to initially retrieve • Optional: w/o, initially starts w/ all records
Basic Hierarchy Query SELECTe.emp_id,e.emp_name,e.mgr_emp_id FROMempe STARTWITHe.mgr_emp_idISNULL CONNECTBYPRIORe.emp_id=e.mgr_emp_id;
Adding the Manager Name SELECTe.emp_idAS"E ID",e.emp_nameAS"Employee", m.emp_idAS"M ID",m.emp_nameAS"Manager" FROM(SELECTe.emp_id,e.mgr_emp_id FROMempe STARTWITHe.mgr_emp_idISNULL CONNECTBYPRIORe.emp_id=e.mgr_emp_id) h JOINempeONh.emp_id=e.emp_id JOINempmONh.mgr_emp_id=m.emp_id ORDERBYe.emp_id;
Start w/ any Record Set SELECTe.emp_id,e.emp_name,e.mgr_emp_id FROMempe STARTWITHe.emp_name='Beth‘ CONNECTBYe.mgr_emp_id=PRIORe.emp_id;
Indicating LEVEL SELECTLEVEL,e.emp_id,e.emp_name,e.mgr_emp_id FROMempe STARTWITHe.emp_name='Beth‘ CONNECTBYPRIORe.emp_id=e.mgr_emp_id;
Use Functions on LEVEL SELECTMAX(level)ASmaxlevel FROMempe STARTWITHe.mgr_emp_idISNULL CONNECTBYPRIORe.emp_id=e.mgr_emp_id;
Aggregate on LEVEL SELECTlevel,COUNT ( emp_id) FROMempe STARTWITHe.mgr_emp_idISNULL CONNECTBYPRIORe.emp_id=e.mgr_emp_id GROUPBYlevel;
Indenting Dependents SELECTLPAD(' ',3 * (level-1)) || e.emp_nameAS"Employee", level,e.emp_id,e.mgr_emp_id FROMempe STARTWITHe.mgr_emp_idISNULL CONNECTBYPRIORe.emp_id=e.mgr_emp_id;
Filter a Hierarchy SELECTLPAD(' ',3 * (level-1)) || e.emp_nameAS"Employee", level,e.emp_id,e.mgr_emp_id FROMempe WHEREe.hire_dt<'1-Jan-2004' STARTWITHe.mgr_emp_idISNULL CONNECTBYPRIORe.emp_id=e.mgr_emp_id;
Top N Levels of Hierarchy SELECTLPAD(' ',3 * (level-1)) || e.emp_nameAS"Employee", level,e.emp_id,e.mgr_emp_id FROMempe WHERElevel<=2 STARTWITHe.mgr_emp_idISNULL CONNECTBYPRIORe.emp_id=e.mgr_emp_id;
Sorting, the Wrong Way SELECTLPAD(' ',3 * (level-1)) || e.emp_nameAS"Employee", level,e.emp_id,e.mgr_emp_id FROMempe STARTWITHe.mgr_emp_idISNULL CONNECTBYPRIORe.emp_id=e.mgr_emp_id ORDERBYemp_name;
Sorting: The SIBLINGS Clause SELECTLPAD(' ',3 * (level-1)) || e.emp_nameAS"Employee", level,e.emp_id,e.mgr_emp_id FROMempe STARTWITHe.mgr_emp_idISNULL CONNECTBYPRIORe.emp_id=e.mgr_emp_id ORDERSIBLINGSBYemp_name;
Display a Path SELECTSUBSTR(SYS_CONNECT_BY_PATH( e.emp_name,' - '),4) AS"Employee Path" FROMempe STARTWITHe.mgr_emp_idISNULL CONNECTBYPRIORe.emp_id=e.mgr_emp_id ORDERSIBLINGSBYemp_name;
The Root for Each Node SELECTe.emp_id,e.emp_nameAS"Employee", CONNECT_BY_ROOTe.emp_nameAS"Top Dog" FROMempe STARTWITHe.mgr_emp_idISNULL CONNECTBYPRIORe.emp_id=e.mgr_emp_id;
Has a Connection to SELECT * FROMempe WHEREe.emp_name='Beth' STARTWITHe.emp_name='Robin‘ CONNECTBYe.emp_id=PRIORe.mgr_emp_id;
Summng Dependent Info SELECT t2.emp_id, t2.emp_name, t2.sal, (SELECTSUM(t1.sal ) FROMempt1 STARTWITHt1.emp_id = t2.emp_id CONNECTBYt1.mgr_emp_id =PRIORt1.emp_id ) ASsum_salary FROMemp t2;
Cycles in a Hierarchy UPDATEempe SETe.mgr_emp_id=22 WHEREe.emp_id=10; SELECTLPAD(' ',3 * (level-1)) || e.emp_nameAS"Employee", level,e.emp_id,e.mgr_emp_id FROMempe STARTWITHe.mgr_emp_id=10 CONNECTBYPRIORe.emp_id=e.mgr_emp_id; 17:08:52 Error: ORA-01436: CONNECT BY loop in user data
Running w/ Errors SELECTLPAD(' ',3 * (level-1)) || e.emp_nameAS"Employee", level,e.emp_id,e.mgr_emp_id FROMempe STARTWITHe.mgr_emp_id=10 CONNECTBYNOCYCLEPRIORe.emp_id =e.mgr_emp_id;
Trapping Cycle Errors SELECTe.emp_id,e.emp_name,CONNECT_BY_ISCYCLE FROMempe STARTWITHe.mgr_emp_id=10 CONNECTBYNOCYCLEPRIORe.emp_id=e.mgr_emp_id; ROLLBACK;
Finding Leaf Nodes SELECTe.emp_id,e.emp_name FROMempe WHERECONNECT_BY_ISLEAF=1 STARTWITHe.mgr_emp_idISNULL CONNECTBYPRIORe.emp_id=e.mgr_emp_id;
Source of Information Mastering Oracle SQL, 2nd Edition Sanjay Mishra & Alan Beaulieu O'Reilly Media, Inc., 2004 ISBN-13: 978-0-596-00632-7 496 pages
Counter SELECTlevel x FROM dual CONNECTBYlevel<=100;
Additional Tricks w/ CONNECT BY • Finding potential flights using an INTERSECT of 2 CONNECT BY queries. • @ http://gennick.com/flight.html SQL Pocket Guide, 2nd Edition By: Jonathan Gennick Publisher: O'Reilly Media, Inc. Pub. Date: April 17, 2006 Print ISBN-13: 978-0-596-52688-7 Pages in Print Edition: 192