2008年12月30日星期二

层次查询

层次查询(connect by查询)
它的语法是:
SELECT *
FROM 
WHERE
START WITH 
CONNECT BY 
ORDER BY col1, col2 ...
其中,start with 表示的是根刻录行,connect by 指定了父记录行和子记录行之间的关系,在层次查询中,条件表达式必须使用prior操作符来指定父记录行,如:
... PRIOR expr = expr
or
... expr = PRIOR expr 
如果connect by 条件是一个组合条件,那么只有一个条件需要prior操作符,如:CONNECT BY last_name != 'King' AND PRIOR employee_id = manager_id不过,connect by 不能包含子查询。
prior是一个二元操作符,最常见的是用于列值相等的比较,它让Oracle使用对应列的父亲行的值。使用非相等比较,极有可能倒致查询陷入无穷循环,以出错终止。
与join的组合, 
如果where子句有join操作,在执行connect by之前会先执行join  
如果where子句没有join操作,会在执行connect by之后再执行这些条件  
Oracle会执行下述步骤来完成connect by操作:
1. 执行条件过滤,取决于是否有join操作
2. 选择层次中满足start with条件的的根行,即层次树中第一层的节点行
3. 选择每个根行的子行,每个子行必须满足connect by条件中对应于根行的条件
4. 选择子行的后代,每次都使用子行与对应的父行进行connect by 匹配
5. 如果where中不含有join操作,那么Oracle将在执行完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
 
举子例子说明,
对emp表,如果以条件“where mgr is NULL”开始,先会产生没有经理的那些行,以这些行作为根,开始搜索,再执行“CONNECT BY PRIOR EMPNO = MGR”,下面是这个查询的具体过程: 
Using EMP, the start with SET is:

scott@ORA8I.WORLD> select ename, empno, mgr from emp
  2  where mgr is null;

ENAME           EMPNO        MGR
---------- ---------- ----------
KING             7839

Now, if we do the "connect by manually" we would find:

scott@ORA8I.WORLD> select ename, empno, mgr
  2  from emp where mgr = 7839;

ENAME           EMPNO        MGR
---------- ---------- ----------
JONES            7566       7839
BLAKE            7698       7839
CLARK            7782       7839

scott@ORA8I.WORLD> 

KINGS empno is the prior empno.  If we build the entire hierarch -- we have:

scott@ORA8I.WORLD> select lpad(' ',level*2,' ')||ename ename, empno, mgr
  2  from emp
  3  START WITH MGR IS NULL
  4  CONNECT BY PRIOR EMPNO = MGR
  5  /

ENAME                EMPNO        MGR
--------------- ---------- ----------
  KING                7839
    JONES             7566       7839
      SCOTT           7788       7566
        ADAMS         7876       7788
      FORD            7902       7566
        SMITH         7369       7902
    BLAKE             7698       7839
      ALLEN           7499       7698
      WARD            7521       7698
      MARTIN          7654       7698
      TURNER          7844       7698
      JAMES           7900       7698
    CLARK             7782       7839
      MILLER          7934       7782

14 rows selected.

没有评论: