http://docs.oracle.com/cd/B19306_01/server.102/b14200/queries003.htm,官方文档(英文版)
If a table contains hierarchical data, then you can select rows in a hierarchical order using the hierarchical query clause: Description of the illustration hierarchical_query_clause.gif
Both the You can further refine a hierarchical query by using the See Also: CONNECT_BY_ROOT for more information about this operator and "Hierarchical Query Examples"Oracle processes hierarchical queries as follows:
Oracle then uses the information from these evaluations to form the hierarchy using the following steps:
To find the children of a parent row, Oracle evaluates the If the Note: In a hierarchical query, do not specify eitherORDER
BY or
GROUP
BY , as they will destroy the hierarchical order of the
CONNECT
BY results. If you want to order rows of siblings of the same parent, then use the
ORDER
SIBLINGS
BY clause. See
order_by_clause.
Hierarchical Query ExamplesCONNECT BY Example The following hierarchical query uses the SELECT employee_id, last_name, manager_id FROM employees CONNECT BY PRIOR employee_id = manager_id; EMPLOYEE_ID LAST_NAME MANAGER_ID ----------- ------------------------- ---------- 101 Kochhar 100 108 Greenberg 101 109 Faviet 108 110 Chen 108 111 Sciarra 108 112 Urman 108 113 Popp 108 200 Whalen 101 ... LEVEL Example The next example is similar to the preceding example, but uses the SELECT employee_id, last_name, manager_id, LEVEL FROM employees CONNECT BY PRIOR employee_id = manager_id; EMPLOYEE_ID LAST_NAME MANAGER_ID LEVEL ----------- ------------------------- ---------- ---------- 101 Kochhar 100 1 108 Greenberg 101 2 109 Faviet 108 3 110 Chen 108 3 111 Sciarra 108 3 112 Urman 108 3 113 Popp 108 3 ... START WITH Examples The next example adds a SELECT last_name, employee_id, manager_id, LEVEL FROM employees START WITH employee_id = 100 CONNECT BY PRIOR employee_id = manager_id ORDER SIBLINGS BY last_name; LAST_NAME EMPLOYEE_ID MANAGER_ID LEVEL ------------------------- ----------- ---------- ---------- King 100 1 Cambrault 148 100 2 Bates 172 148 3 Bloom 169 148 3 Fox 170 148 3 Kumar 173 148 3 Ozer 168 148 3 Smith 171 148 3 De Haan 102 100 2 Hunold 103 102 3 Austin 105 103 4 Ernst 104 103 4 Lorentz 107 103 4 Pataballa 106 103 4 Errazuriz 147 100 2 Ande 166 147 3 Banda 167 147 3 ... In the UPDATE employees SET manager_id = 145 WHERE employee_id = 100; SELECT last_name "Employee", LEVEL, SYS_CONNECT_BY_PATH(last_name, '/') "Path" FROM employees WHERE level <= 3 AND department_id = 80 START WITH last_name = 'King' CONNECT BY PRIOR employee_id = manager_id AND LEVEL <= 4; 2 3 4 5 6 7 ERROR: ORA-01436: CONNECT BY loop in user data The SELECT last_name "Employee", CONNECT_BY_ISCYCLE "Cycle", LEVEL, SYS_CONNECT_BY_PATH(last_name, '/') "Path" FROM employees WHERE level <= 3 AND department_id = 80 START WITH last_name = 'King' CONNECT BY NOCYCLE PRIOR employee_id = manager_id AND LEVEL <= 4; Employee Cycle LEVEL Path ------------------------- ------ ------ ------------------------- Russell 1 2 /King/Russell Tucker 0 3 /King/Russell/Tucker Bernstein 0 3 /King/Russell/Bernstein Hall 0 3 /King/Russell/Hall Olsen 0 3 /King/Russell/Olsen Cambrault 0 3 /King/Russell/Cambrault Tuvault 0 3 /King/Russell/Tuvault Partners 0 2 /King/Partners King 0 3 /King/Partners/King Sully 0 3 /King/Partners/Sully McEwen 0 3 /King/Partners/McEwen ... CONNECT_BY_ROOT Examples The following example returns the last name of each employee in department 110, each manager above that employee in the hierarchy, the number of levels between manager and employee, and the path between the two: SELECT last_name "Employee", CONNECT_BY_ROOT last_name "Manager", LEVEL-1 "Pathlen", SYS_CONNECT_BY_PATH(last_name, '/') "Path" FROM employees WHERE LEVEL > 1 and department_id = 110 CONNECT BY PRIOR employee_id = manager_id; Employee Manager Pathlen Path --------------- ------------ ---------- ----------------------------------- Higgins Kochhar 1 /Kochhar/Higgins Gietz Kochhar 2 /Kochhar/Higgins/Gietz Gietz Higgins 1 /Higgins/Gietz Higgins King 2 /King/Kochhar/Higgins Gietz King 3 /King/Kochhar/Higgins/Gietz The following example uses a SELECT name, SUM(salary) "Total_Salary" FROM ( SELECT CONNECT_BY_ROOT last_name as name, Salary FROM employees WHERE department_id = 110 CONNECT BY PRIOR employee_id = manager_id) GROUP BY name; NAME Total_Salary ------------------------- ------------ Gietz 8300 Higgins 20300 King 20300 Kochhar 20300 | 如 果表中包含分层数据,那么你可以选择使用层次查询子句的等级秩序的行: START WITH:指定层次的根行(次)。 CONNECT BY:指定父行和子行的层级之间的关系。
两者中的CONNECT BY条件和先表达可以采取不相关子查询的形式。然而,现有的表达不能引用序列。也就是说,CURRVAL和NEXTVAL不是之前有效表达。 您可以通过使用CONNECT_BY_ROOT 操作有资格在选择列表中的列进一步细化分层查询。此操作通过返回,不仅直接父行,但在层次结构中的所有祖先行延伸层次查询的CONNECT BY[上一页]状态的功能。 另请参见: CONNECT_BY_ROOT有关此操作符和“分层查询示例”的详细信息 Oracle进程分层查询,如下所示: 一个连接,如果存在的话,首先评估是否加入在FROM子句或WHERE子句,谓词中指定。 在CONNECT BY条件进行评估。 任何剩余的WHERE子句谓词进行评估。 甲骨文然后使用这些评价的信息通过以下步骤而形成的层次结构: 甲骨文选择层次的根行(S) - 满足与状态的开始的那些行。 甲骨文选择子行每一根一行。每个子行必须满足CONNECT的条件BY条件相对于根行之一。 甲骨文选择连续几代的子行。 Oracle首先选择在步骤2中返回的行的孩子,那么这些孩子的孩子,等等。甲骨文总是通过评估CONNECT BY条件相对于当前父行选择孩子。 如果查询包含没有加入WHERE子句,则Oracle消除了等级不符合WHERE子句条件的所有行。甲骨文评估该条件为每一行单独的,而不是除去行不满足该条件的所有的孩子。 Oracle返回在图9-1所示的顺序行。在该图中,儿童出现父母下面。对于层次树的说明,请参阅图3-1,“层次树”。 图9-1层次查询 图9-1说明如下 “图9-1分层查询”的说明 为了找到一个父行的孩子,甲骨文评估CONNECT事先表达条件父行及其他表达式表中的每一行。排在其条件为真都是父母的孩子。在CONNECT BY条件可以包含其他的条件,以进一步筛选查询所选择的行。在CONNECT BY条件不能包含子查询。 如果在CONNECT BY条件导致在层次结构中的循环,那么Oracle将返回一个错误。如果一行是另一行的两个父(或祖父母或直接祖先)和一个孩子(或孙子或直系后裔)出现一个循环。 注意: 在一个分层查询,也可以不指定ORDER BY或GROUP BY,因为它们会破坏CONNECT的等级秩序BY结果。如果您想订购的行同父母的兄弟姐妹,然后使用ORDER SIBLINGS BY子句。见order_by_clause。 分层查询的例子 CONNECT BY示例下面的分层查询使用CONNECT BY子句定义员工和管理者之间的关系: SELECT employee_id, last_name, manager_id FROM employees CONNECT BY PRIOR employee_id = manager_id; EMPLOYEE_ID LAST_NAME MANAGER_ID ----------- ------------------------- ---------- 101 Kochhar 100 108 Greenberg 101 109 Faviet 108 110 Chen 108 111 Sciarra 108 112 Urman 108 113 Popp 108 200 Whalen 101 ... 级别实例下面的例子是类似上面的例子,但使用 LEVEL 伪列显示父和子行: SELECT employee_id, last_name, manager_id, LEVEL FROM employees CONNECT BY PRIOR employee_id = manager_id; EMPLOYEE_ID LAST_NAME MANAGER_ID LEVEL ----------- ------------------------- ---------- ---------- 101 Kochhar 100 1 108 Greenberg 101 2 109 Faviet 108 3 110 Chen 108 3 111 Sciarra 108 3 112 Urman 108 3 113 Popp 108 3 ... START WITH例子下面的例子增加一个START WITH子句来指定一个根一行的层次结构和ORDER BY子句使用姐弟俩关键字保留层次结构中排序: SELECT last_name, employee_id, manager_id, LEVEL FROM employees START WITH employee_id = 100 CONNECT BY PRIOR employee_id = manager_id ORDER SIBLINGS BY last_name; LAST_NAME EMPLOYEE_ID MANAGER_ID LEVEL ------------------------- ----------- ---------- ---------- King 100 1 Cambrault 148 100 2 Bates 172 148 3 Bloom 169 148 3 Fox 170 148 3 Kumar 173 148 3 Ozer 168 148 3 Smith 171 148 3 De Haan 102 100 2 Hunold 103 102 3 Austin 105 103 4 Ernst 104 103 4 Lorentz 107 103 4 Pataballa 106 103 4 Errazuriz 147 100 2 Ande 166 147 3 Banda 167 147 3 ... 在HR.EMPLOYEES表,员工史蒂芬国王是该公司的负责人,也没有经理。在他的员工是约翰·罗素,谁是部门80如果我们更新了员工表设置罗素作为国王的经理,我们将创建的数据循环的经理: UPDATE employees SET manager_id = 145 WHERE employee_id = 100; SELECT last_name "Employee", LEVEL, SYS_CONNECT_BY_PATH(last_name, '/') "Path" FROM employees WHERE level <= 3 AND department_id = 80 START WITH last_name = 'King' CONNECT BY PRIOR employee_id = manager_id AND LEVEL <= 4; 2 3 4 5 6 7 ERROR: ORA-01436: CONNECT BY loop in user data 在连接NOCYCLE参数BY条件导致的Oracle返回的行,尽管循环。该CONNECT_BY_ISCYCLE伪显示哪些行包含循环: SELECT last_name "Employee", CONNECT_BY_ISCYCLE "Cycle", LEVEL, SYS_CONNECT_BY_PATH(last_name, '/') "Path" FROM employees WHERE level <= 3 AND department_id = 80 START WITH last_name = 'King' CONNECT BY NOCYCLE PRIOR employee_id = manager_id AND LEVEL <= 4; Employee Cycle LEVEL Path ------------------------- ------ ------ ------------------------- Russell 1 2 /King/Russell Tucker 0 3 /King/Russell/Tucker Bernstein 0 3 /King/Russell/Bernstein Hall 0 3 /King/Russell/Hall Olsen 0 3 /King/Russell/Olsen Cambrault 0 3 /King/Russell/Cambrault Tuvault 0 3 /King/Russell/Tuvault Partners 0 2 /King/Partners King 0 3 /King/Partners/King Sully 0 3 /King/Partners/Sully McEwen 0 3 /King/Partners/McEwen ... CONNECT_BY_ROOT示例下面的示例返回110部每位员工的姓名,该员工在层次结构上的每个经理,经理和员工之间的级别数,以及两者之间的路径: SELECT last_name "Employee", CONNECT_BY_ROOT last_name "Manager", LEVEL-1 "Pathlen", SYS_CONNECT_BY_PATH(last_name, '/') "Path" FROM employees WHERE LEVEL > 1 and department_id = 110 CONNECT BY PRIOR employee_id = manager_id; Employee Manager Pathlen Path --------------- ------------ ---------- ----------------------------------- Higgins Kochhar 1 /Kochhar/Higgins Gietz Kochhar 2 /Kochhar/Higgins/Gietz Gietz Higgins 1 /Higgins/Gietz Higgins King 2 /King/Kochhar/Higgins Gietz King 3 /King/Kochhar/Higgins/Gietz 下面的示例使用GROUP BY子句返回的110部每位员工,而员工在层次结构下的所有雇员的工资总额: SELECT name, SUM(salary) "Total_Salary" FROM ( SELECT CONNECT_BY_ROOT last_name as name, Salary FROM employees WHERE department_id = 110 CONNECT BY PRIOR employee_id = manager_id) GROUP BY name; NAME Total_Salary ------------------------- ------------ Gietz 8300 Higgins 20300 King 20300 Kochhar 20300 |