In its simplest form a hierarchical query needs a definition of how each child relates to its parent. This is defined using the CONNECT BY .. PRIOR clause, which defines how the current row (child) relates to a prior row (parent). In addition, the START WITH clause can be used to define the root node(s) of the hierarchy. Hierarchical queries come with operators, pseudocolumns and functions to help make sense of the hierarchy.
LEVEL : The position in the hierarchy of the current row in relation to the root node.
CONNECT_BY_ROOT : Returns the root node(s) associated with the current row.
SYS_CONNECT_BY_PATH : Returns a delimited breadcrumb from root to the current row.
CONNECT_BY_ISLEAF : Indicates if the current row is a leaf node.
ORDER SIBLINGS BY : Applies an order to siblings, without altering the basic hierarchical structure of the data returned by the query.
The following query gives an example of these items based on the previously defined test table.
SET PAGESIZE 20 LINESIZE 110 COLUMN tree FORMAT A20 COLUMN path FORMAT A20
SELECT id, parent_id, RPAD('.', (level-1)*2, '.') || id AS tree, level, CONNECT_BY_ROOT id AS root_id, LTRIM(SYS_CONNECT_BY_PATH(id, '-'), '-') AS path, CONNECT_BY_ISLEAF AS leaf FROM tab1 STARTWITH parent_id ISNULL CONNECTBY parent_id = PRIOR id ORDER SIBLINGS BY id;
It is possible for a hierarchy to be cyclical, which can represent a problem when querying the data.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
-- Create a cyclic reference UPDATE tab1 SET parent_id =9WHERE id =1; COMMIT;
SELECT id, parent_id, RPAD('.', (level-1)*2, '.') || id AS tree, level, CONNECT_BY_ROOT id AS root_id, LTRIM(SYS_CONNECT_BY_PATH(id, '-'), '-') AS path, CONNECT_BY_ISLEAF AS leaf FROM tab1 STARTWITH id =1 CONNECTBY parent_id = PRIOR id ORDER SIBLINGS BY id; ERROR: ORA-01436: CONNECTBY loop inuser data
To simplify matters, the CONNECT BY NOCYCLE clause tells the database not to traverse cyclical hierarchies. In this case the CONNECT_BY_ISCYCLE function indicates which record is responsible for the cycle.
We can now use the NOCYCLE option and check the results of the CONNECT_BY_ISCYCLE function.
SELECT id, parent_id, RPAD('.', (level-1)*2, '.') || id AS tree, level, CONNECT_BY_ROOT id AS root_id, LTRIM(SYS_CONNECT_BY_PATH(id, '-'), '-') AS path, CONNECT_BY_ISLEAF AS leaf, CONNECT_BY_ISCYCLE AScycle FROM tab1 STARTWITH id =1 CONNECTBY NOCYCLE parent_id = PRIOR id ORDER SIBLINGS BY id;