The START WITH...CONNECT BY clause can be used to select
data that has a hierarchical relationship. Such data is usually in the form
of some parent child relationship e.g. manager to employee relationship.
START WITH condition_1
CONNECT BY PRIOR condition_2
Parameters
- condition_1
The condition clause in the START WITH is used to
specify the relationship between parent rows and child rows of the hierarchy.
- condition_2
The condition in the CONNECT BY PRIOR clause is used to identify the row(s) to be used as the root(s) of a
hierarchical query.
To find the children of a parent row, the clause evaluates the PRIOR expression of the CONNECT BY
condition for the parent row and the other expression for each row in the table. Rows for which the condition is true are the children
of the parent. The CONNECT BY condition can contain other conditions to further filter the rows selected by the query.
The CONNECT BY condition cannot contain a subquery.
CONNECT BY PRIOR Clause
It specifies a condition that identifies the relationship between parent rows and child rows of the hierarchy.
START WITH Clause
It specifies a condition that identifies the row(s) to be used as the root(s) of a hierarchical query.
PRIOR Clause
In a hierarchical query, one expression in condition must be qualified with
the PRIOR operator to refer to the parent row. For example,
... PRIOR expr = expr
or
... expr = PRIOR expr
PRIOR is a unary operator and has the same precedence as the unary + and - arithmetic operators.
It evaluates the immediately following expression for the parent row of the current row in a hierarchical query.
PRIOR is most commonly used when comparing column values with the equality operator.
(The PRIOR keyword can be on either side of the operator.) PRIOR causes
EnterpriseDB to use the value of the parent row in the column. Operators other than the equal sign (=) are
theoretically possible in CONNECT BY clauses. However, the conditions created by these other operators can result
in an infinite loop through the possible combinations. In this case, EnterpriseDB detects the loop at
run time and returns an error.
Processing of Hierarchical Queries
The processing of hierarchical queries is as follows:
A join, if present, is evaluated first, whether the join is specified in the FROM
clause or with WHERE clause predicates.
The CONNECT BY condition is evaluated.
Any remaining WHERE clause predicates are evaluated.
EnterpriseDB then uses the information from these evaluations to form the hierarchy using the
following steps:
It selects the root row(s) of the hierarchy-those rows that satisfy the START WITH condition.
It selects the child rows of each root row. Each child row must satisfy the
condition of the CONNECT BY clause with respect to one of the root rows.
It selects successive generations of child rows. EnterpriseDB
first selects the children of the rows returned in step 2, and then the children of those children, and so on.
It always selects children by evaluating the CONNECT BY condition with respect to a current parent row.
It selects successive generations of child rows. EnterpriseDB
first selects the children of the rows returned in step 2, and then the children of those children, and so on.
It always selects children by evaluating the CONNECT BY condition with respect to a current parent row.
If the query contains a WHERE clause without a join, then EnterpriseDB
eliminates all rows from the hierarchy that do not satisfy the condition of the WHERE clause.
It evaluates this condition for each row individually, rather than removing all the children of a row that does not
satisfy the condition.
It returns the rows in the order shown in the following figure. In the diagram, children appear below their parents.
To find the children of a parent row, EnterpriseDB evaluates the PRIOR
expression of the CONNECT BY condition for the parent row and the other expression for each row in
the table. Rows for which the condition is true are the children of the parent. The CONNECT BY
condition can contain other conditions to further filter the rows
selected by the query. The CONNECT BY condition cannot contain a subquery.
If the CONNECT BY condition results in a loop in the hierarchy, then it returns
an error. A loop occurs if one row is both the parent (or grandparent or direct
ancestor) and a child (or a grandchild or a direct descendent) of another row.
Level Pseudo Column
For each row returned by a hierarchical query, the LEVEL pseudo column returns 1 for a root row,
2 for a child of a root, and so on.
START WITH... CONNECT BY Clause
The START WITH... CONNECT BY clause can be used to select data that has a hierarchical relationship,
i.e. usually some kind of parent Child relationship, e.g. manager->employee.
START WITH is used to specify the root of the hierarchy,
typically the element which has no parent, although other elements can be chosen as the root as well to generate partial hierarchies.
CONNECT BY is used to specify the recurse-condition. In order to define hierarchies,
the recurse-condition can make use of the keyword prior:
CONNECT BY PRIOR foo = bar;
This construct establishes recursion. All records that are part of the next lower hierarchical level are found by having bar = foo.
foo is a value found in the current hierarchical level.
There is a pseudo-column LEVEL available which can be used to determine the hierarchical level of any row.
LEVEL can not be used in any expression/function.
Example (Using EnterpriseDB Sample Database)
The following example illustrates the use of the START WITH.....CONNECT BY clause:
SELECT LEVEL, ename, empno, mgr
FROM emp
START WITH mgr IS NULL
CONNECT BY PRIOR empno = mgr;
Output
The output of the above query is as follows:
level | ename | empno | mgr
-------+--------+-------+------
1 | KING | 7839 |
2 | JONES | 7566 | 7839
3 | SCOTT | 7788 | 7566
4 | ADAMS | 7876 | 7788
3 | FORD | 7902 | 7566
4 | SMITH | 7369 | 7902
2 | BLAKE | 7698 | 7839
3 | ALLEN | 7499 | 7698
3 | WARD | 7521 | 7698
3 | MARTIN | 7654 | 7698
3 | TURNER | 7844 | 7698
3 | JAMES | 7900 | 7698
2 | CLARK | 7782 | 7839
3 | MILLER | 7934 | 7782
1 | user | 1 |
(15 rows)
To use LEVEL in expressions/functions there exists a work-around.
The query can be used as a subquery, then the outer query can use LEVEL as a regular column in expressions/functions.
Simple Example
Another example that uses the START WITH.....CONNECT BY clause is as follows:
CREATE TABLE Geometry
(
name VARCHAR,
typeof VARCHAR
);
INSERT INTO Geometry VALUES( 'Shape', NULL );
INSERT INTO Geometry VALUES( 'Circle', 'Shape' );
INSERT INTO Geometry VALUES( 'Polygon', 'Shape' );
INSERT INTO Geometry VALUES( 'Triangle', 'Polygon' );
INSERT INTO Geometry VALUES( 'Quadrilateral', 'Polygon' );
INSERT INTO Geometry VALUES( 'Rectangle', 'Quadrilateral' );
INSERT INTO Geometry VALUES( 'Square', 'Rectangle' );
INSERT INTO Geometry VALUES( 'Parallelogram', 'Quadrilateral' );
INSERT INTO Geometry VALUES( 'Rhombus', 'Parallelogram' );
INSERT INTO Geometry VALUES( 'Hexagon', 'Polygon' );
SELECT LEVEL, LPAD(' ',3*(LEVEL - 1)) || name AS "Shape", TYPEOF AS "is a type of"
FROM (
SELECT LEVEL, name, TYPEOF
FROM Geometry
START WITH TYPEOF IS NULL
CONNECT BY PRIOR name = TYPEOF
) AS subquery;
DROP TABLE Geometry;
Output
The output of the above query is as follows:
level | Shape | is a type of
-------+------------------------+---------------
1 | Shape |
2 | Circle | Shape
2 | Polygon | Shape
3 | Triangle | Polygon
3 | Quadrilateral | Polygon
4 | Rectangle | Quadrilateral
5 | Square | Rectangle
4 | Parallelogram | Quadrilateral
5 | Rhombus | Parallelogram
3 | Hexagon | Polygon
(10 rows)
Example (Using EnterpriseDB Sample Database)
SELECT LEVEL, LPAD(' ',3*(LEVEL - 1)) || ename AS "Employee", empno, mgr
FROM (
SELECT LEVEL, ename, empno, mgr
FROM emp
START WITH mgr IS NULL
CONNECT BY PRIOR empno = mgr
) AS subquery;
Output
The output of the above query is as follows:
level | Employee | empno | mgr
-------+----------------+-------+------
1 | KING | 7839 |
2 | JONES | 7566 | 7839
3 | SCOTT | 7788 | 7566
4 | ADAMS | 7876 | 7788
3 | FORD | 7902 | 7566
4 | SMITH | 7369 | 7902
2 | BLAKE | 7698 | 7839
3 | ALLEN | 7499 | 7698
3 | WARD | 7521 | 7698
3 | MARTIN | 7654 | 7698
3 | TURNER | 7844 | 7698
3 | JAMES | 7900 | 7698
2 | CLARK | 7782 | 7839
3 | MILLER | 7934 | 7782
1 | user | 1 |
(15 rows)
Example
SELECT LEVEL, ename, empno, mgr
FROM emp
START WITH empno = 7788
CONNECT BY PRIOR empno = mgr;
Output
The output of the above query is as follows:
level | ename | empno | mgr
-------+-------+-------+------
1 | SCOTT | 7788 | 7566
2 | ADAMS | 7876 | 7788
(2 rows)
Example
SELECT LEVEL, ename, mgr
FROM emp
START WITH empno= 7839
CONNECT BY PRIOR empno=mgr;
Output
The output of the above query is as follows:
level | ename | mgr
-------+--------+------
1 | KING |
2 | JONES | 7839
3 | SCOTT | 7566
4 | ADAMS | 7788
3 | FORD | 7566
4 | SMITH | 7902
2 | BLAKE | 7839
3 | ALLEN | 7698
3 | WARD | 7698
3 | MARTIN | 7698
3 | TURNER | 7698
3 | JAMES | 7698
2 | CLARK | 7839
3 | MILLER | 7782
(14 rows)