New CONNECT by Features in Oracle Database 10g

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 4

New CONNECT BY Features in Oracle Database 10g

http://www.oracle.com/technology/oramag/webcolumns/2003/techarticl...

(Sign In / Register for a free Oracle Web account)

secure search Getting Started

Technology Network Sample Code

PRODUCTS
Database Middleware Developer Tools Enterprise Management Applications Technology Extensions and Plugins Products A-Z

Downloads

Documentation

Forums

Articles

Tutorials

Inside Oracle Database 10g

New CONNECT BY Features in Oracle Database 10g


By Jonathan Gennick OTN Member since 2001 Oracle Database 10g enhances support for querying hierarchical, or tree-structured, data Recently I wrote about Oracle's support for hierarchical queries in an OTN article titled Querying Hierarchies: Top-of-the-Line Support. While writing that article, I learned about some exciting, new features in Oracle Database 10g that strengthen Oracle's already robust support for querying tree-structured data. Unfortunately, I couldn't mention those new features because they were still in beta. Since then, I've been rather impatiently biding my time until the product announcement, and now the day has come when I can speak freely. This article details the three new CONNECT BY features in Oracle Database 10g. The examples are based on the same table, and use the same data, as those in my previous article. You may wish to read that article to refresh your memory as to how CONNECT BY queries work.

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

Root of the Matter


If you read my previous article, you've seen how the PRIOR operator is used in hierarchical queries to return column data from a parent row. Sometimes it's handy to be able to go all the way back to the root row. New in Oracle Database 10g, the CONNECT_BY_ROOT operator enables you to reference root-row values from anywhere in a hierarchy. One use for CONNECT_BY_ROOT is to identify all products containing a given part. Suppose you work for a manufacturing company. You've just discovered that part 1019 is defective, and the Consumer Product Safety Commission has ordered you to recall all products sold containing that part. Your first task is to determine just which products you need to worry about. You could begin by issuing the following query, as a first attempt:

Legal | Privacy SELECT COUNTRY

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

New CONNECT BY Features in Oracle Database 10g

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.

Getting to the Bottom of Things


Hierarchical data is often deeply nested. Consider the problem of presenting a mechanic with a nested list of assemblies and parts that go into a car. Cars contain large numbers of parts. Rarely will a mechanic want to see details on all the assemblies and parts in a car at once. Not only would such a list be overwhelming, but it's very inefficient to retrieve such a complete list of assemblies and parts from a database and transmit that information across the network when the user wants only a fraction of that data. Instead, you might choose to present only the top-level of assemblies to begin with, and let users drill-down from there. For example, perhaps you initially present our user with the results of the following query:

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:

SELECT ASSEMBLY_ID, RPAD(' ', 2*(LEVEL-1)) || assembly_name assembly_name,

2 di 4

15/02/2007 11.47

New CONNECT BY Features in Oracle Database 10g

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.

Getting Out of the Loop


Whenever you work with hierarchical data, there's the chance you might encounter a hierarchy that's circular. For example, someone might set the parent of an automobile to be a spark plug:

UPDATE bill_of_materials SET parent_assembly = 113 WHERE assembly_id=100;


An attempt to query the tree of assemblies for "Automobile" will now fail:

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

Combustion Engine Piston Air Filter Spark Plug Block

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

New CONNECT BY Features in Oracle Database 10g

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.

Getting Work Done


The new CONNECT BY features in Oracle Database 10gCONNECT_BY_ROOT, CONNECT_BY_ISLEAF, and CONNECT_BY_ISCYCLEare well thought out and welcome improvements to Oracle's hierarchical query support. These features solve common and longstanding problems inherent in querying hierarchical data, problems that are difficult to solve otherwise. Using these features, you can focus less on implementation details and more on the big picture of what you need to accomplish, getting work done that you need done simply and without fuss. Jonathan Gennick (jonathan@gennick.com) is an experienced Oracle DBA and an Oracle Certified Professional. He resides in Munising, Mich., and just finished writing the Oracle Regular Expression Pocket Reference (O'Reilly & Associates, 2003) with Peter Linsley. Jonathan also runs an email list for articles about Oracle, which you can subscribe to by visiting http://gennick.com.
E-mail this page Printer View

4 di 4

15/02/2007 11.47

You might also like