Professional Documents
Culture Documents
New CONNECT by Features in Oracle Database 10g
New CONNECT by Features in Oracle Database 10g
New CONNECT by Features in Oracle Database 10g
http://www.oracle.com/technology/oramag/webcolumns/2003/techarticl...
PRODUCTS
Database Middleware Developer Tools Enterprise Management Applications Technology Extensions and Plugins Products A-Z
Downloads
Documentation
Forums
Articles
Tutorials
TECHNOLOGIES
BI & Data Warehousing Java Linux .NET Office PHP Security Service-Oriented Architecture XML Windows Server System Technologies A-Z
COMMUNITY
About OTN Oracle ACEs Regional Directors Blogs Podcasts TechBlast Newsletter Oracle Magazine Oracle 10g Books Certification User Groups Partner White Papers
SELECT assembly_id, assembly_name FROM bill_of_materials WHERE part_number = 1019 START WITH parent_assembly IS NULL CONNECT BY parent_assembly = PRIOR assembly_id; ASSEMBLY_ID ASSEMBLY_NAME ----------- ----------------------141 Lock 144 Lock
These results look plausible, but there's one problem with them. Part 1019 is a lock, and it's indeed used in two lock assemblies. However, those lock assemblies are in turned used within left and right door assemblies, which are in turn used in a body assembly, which is ultimately used to make a car, and it's cars that we sell and care about. You don't want the immediate parent assembly for part 1019; you want the ultimate parent for part 1019. Fortunately, your DBA just upgraded to Oracle Database 10g, so you can take advantage of the new CONNECT_BY_ROOT operator:
SELECT DISTINCT CONNECT_BY_ROOT assembly_id, CONNECT_BY_ROOT assembly_name FROM bill_of_materials WHERE part_number = 1019 START WITH parent_assembly IS NULL CONNECT BY parent_assembly = PRIOR assembly_id; CONNECT_BY_ROOTASSEMBLY_ID CONNECT_BY_ROOTASSEMBLY -------------------------- -----------------------
1 di 4
15/02/2007 11.47
http://www.oracle.com/technology/oramag/webcolumns/2003/techarticl...
100 Automobile
The bulk of this query is the same as before. There are just two differences: the use of DISTINCT, and the presence of CONNECT_BY_ROOT in front of each column name in the SELECT list. The CONNECT_BY_ROOT operator yields the ultimate parent assembly IDs and names for the part we're concerned about. The DISTINCT keyword prevents a product from being listed multiple times if it contains the same part in more that one assembly. It turns out that your automobile contains locks in both its right and left doors.
SELECT ASSEMBLY_ID, RPAD(' ', 2*(LEVEL-1)) || assembly_name assembly_name, quantity FROM bill_of_materials WHERE LEVEL <= 2 START WITH assembly_id = 100 CONNECT BY parent_assembly = PRIOR assembly_id; ASSEMBLY_ID ----------100 110 120 130 ASSEMBLY_NAME ------------Automobile Combustion Engine Body Interior QUANTITY ---------1 1 1
Looking at this first level of assemblies, our users can now decide whether they want to drill down further. You can enable drill-down by implementing assembly names as web links when there's more data to be seen, or you can implement a tree control such as is commonly seen in Windows applications. But wait! How do you know when there's more data for an assembly? When is drill-down possible? You could let users try to drill-down into any assembly, and give them a "no more data" message when they try to drill-down from the bottom of the hierarchy, but that's an inelegant solution certain to frustrate them. It's better to know ahead of time whether drill-down is possible. Oracle Database 10g enables us to do that via the CONNECT_BY_ISLEAF pseudocolumn. You can use the following query to begin:
SELECT ASSEMBLY_ID, RPAD(' ', 2*(LEVEL-1)) || assembly_name assembly_name, quantity, CONNECT_BY_ISLEAF FROM bill_of_materials WHERE LEVEL <= 2 START WITH assembly_id = 100 CONNECT BY parent_assembly = PRIOR assembly_id; ASSEMBLY_ID ASSEMBLY_NAME QUANTITY CONNECT_BY_ISLEAF ----------- ----------------------- ---------- ----------------100 Automobile 0 110 Combustion Engine 1 0 120 Body 1 0 130 Interior 1 0
The zeros returned by CONNECT_BY_ISLEAF indicate that none of the assemblies shown in this listing are leaf nodes. In other words, it's valid to drill down into any of them. Say a user drills down into Combustion Engine. You then issue the following query to get the subassemblies making up an engine:
2 di 4
15/02/2007 11.47
http://www.oracle.com/technology/oramag/webcolumns/2003/techarticl...
quantity, CONNECT_BY_ISLEAF FROM bill_of_materials WHERE LEVEL = 2 START WITH assembly_id = 110 CONNECT BY parent_assembly = PRIOR assembly_id; ASSEMBLY_ID ASSEMBLY_NAME QUANTITY CONNECT_BY_ISLEAF ----------- ----------------------- ---------- ----------------111 Piston 6 1 112 Air Filter 1 1 113 Spark Plug 6 1 114 Block 1 1 115 Starter System 1 0
This query is almost the same as before. The START WITH assembly_id value has been changed to 110, for Combustion Engine, and the query specifically asks for LEVEL = 2. You don't need LEVEL = 1 at this point, because that would return the row for Combustion Engine again, and you already have that row. This time, you see two values for CONNECT_BY_ISLEAF. The value of 1 for Piston, Air Filter, Spark Plug and Block indicates that those assemblies are leaf nodes under which no more assemblies are to be found. Knowing that, you can adjust our display so the user knows not to bother drilling down on those elements. On the other hand, the Starter System has a CONNECT_BY_ISLEAF value of 0, indicating that there are still subassemblies to be retrieved.
SELECT RPAD(' ', 2*(LEVEL-1)) || assembly_name assembly_name, quantity FROM bill_of_materials START WITH assembly_id = 100 CONNECT BY parent_assembly = PRIOR assembly_id; ERROR: ORA-01436: CONNECT BY loop in user data
When you get an error message like this, you can use the CONNECT_BY_ISCYCLE pseudocolumn to locate the row (or rows) causing the problem. To do that, you must also add the NOCYCLE keyword to the CONNECT BY clause, to prevent the database from following any loops in the hierarchy:
SELECT RPAD(' ', 2*(LEVEL-1)) || assembly_name assembly_name, quantity, CONNECT_BY_ISCYCLE Next Steps FROM bill_of_materials START WITH assembly_id = 100 Download the Oracle Database: CONNECT BY NOCYCLE parent_assembly = PRIOR assembly_id; ASSEMBLY_NAME QUANTITY CONNECT_BY_ISCYCLE Visit the Oracle Database 10g ------------------------------ --------------------------Product Page:: Automobile 0
/products/database/index.html
/software/products/oracle9i/index.html
1 6 1 6 1
0 0 0 1 0
Note that CONNECT_BY_ISCYCLE returns a 1 for the "Spark Plug" row. When you use
3 di 4
15/02/2007 11.47
http://www.oracle.com/technology/oramag/webcolumns/2003/techarticl...
NOCYCLE, the database keeps track of its path through the hierarchy, constantly checking to ensure it's not following a loop. After working it's way from "Automobile" to "Combustion Engine" to "Spark Plug", the database sees that "Spark Plug's" child is "Automobile," a row that is already in the path taken to get to "Spark Plug". Such a row represents a loop. NOCYCLE prevents the database from following the loop, and CONNECT_BY_ISCYCLE returns a 1 to identify the row in which the loop occurs. Now that you know where the problem is, you can fix it.
4 di 4
15/02/2007 11.47