Oracle Connect By Start With 總結==轉帖

 Oracle Connect By Start With 總結==轉帖 app

 

Oracle 實在太強了,本篇文章詳細介紹了Oracle的遞歸查詢語法,利用此語法,能夠方便地實現遞歸的雙向查詢:ide

-- Tirle        : Recursion query for TREE with "connect by/start with"
-- Author       : Rake Gao
-- Create Date : 2005-08-22
-- Version      : 2.0
-- Last Modify : 2005-08-22測試

目 錄
1、測試準備
2、實現各類查詢要求
3、要點總結spa


正 文
1、測試準備
一、先假設有以下部門結構。
       1
     / \
    2    3 
   /\    /|\
4 5 6 7 8orm

二、而後創建測試表和數據。
drop table t_dept_temp;
create table t_dept_temp(
DEPT_ID    NUMBER(2)    NOT NULL,
PARENT_ID NUMBER(2)    ,
DEPT_NAME VARCHAR2(10) ,
AMOUNT     NUMBER(3)           --人數
);
delete t_dept_temp;
insert into t_dept_temp (DEPT_ID,PARENT_ID,DEPT_NAME,AMOUNT) values (1,null,'1'    ,2);
insert into t_dept_temp (DEPT_ID,PARENT_ID,DEPT_NAME,AMOUNT) values (2,1   ,'1-2' ,15);
insert into t_dept_temp (DEPT_ID,PARENT_ID,DEPT_NAME,AMOUNT) values (3,1   ,'1-3' ,8);
insert into t_dept_temp (DEPT_ID,PARENT_ID,DEPT_NAME,AMOUNT) values (4,2   ,'1-2-4',10);
insert into t_dept_temp (DEPT_ID,PARENT_ID,DEPT_NAME,AMOUNT) values (5,2   ,'1-2-5',9);
insert into t_dept_temp (DEPT_ID,PARENT_ID,DEPT_NAME,AMOUNT) values (6,3   ,'1-3-6',17);
insert into t_dept_temp (DEPT_ID,PARENT_ID,DEPT_NAME,AMOUNT) values (7,3   ,'1-3-7',5);
insert into t_dept_temp (DEPT_ID,PARENT_ID,DEPT_NAME,AMOUNT) values (8,3   ,'1-3-8',6);
commit;排序

SQL> select * from t_dept_temp;遞歸

DEPT_ID PARENT_ID DEPT_NAME AMOUNT
------- --------- ---------- ------
      1           1               2
      2         1 1-2            15
      3         1 1-3             8
      4         2 1-2-4          10
      5         2 1-2-5           9
      6         3 1-3-6          17
      7         3 1-3-7           5
      8         3 1-3-8           6ci

三、調整一下輸出格式
col DEPT_ID format A10;it

2、接下來實現各類查詢要求
一、部門2及其全部下級部門。
SELECT LPAD(' ',2*(LEVEL - 1), ' ')||DEPT_ID AS DEPT_ID,
       PARENT_ID,DEPT_NAME,AMOUNT
FROM t_dept_temp
CONNECT BY PARENT_ID = PRIOR DEPT_ID -- 找出全部PARENT_ID等於當前記錄DEPT_ID的記錄。
START WITH DEPT_ID = 2                -- 從部門2開始遞歸查詢。
;
DEPT_ID    PARENT_ID DEPT_NAME AMOUNT
---------- --------- ---------- ------
2                  1 1-2            15
4                2 1-2-4          10
5                2 1-2-5           9io

二、部門4及其全部上級部門
SELECT LPAD(' ',2*(LEVEL - 1), ' ')||DEPT_ID AS DEPT_ID,
       PARENT_ID,DEPT_NAME,AMOUNT
FROM T_DEPT_TEMP
CONNECT BY PRIOR PARENT_ID = DEPT_ID -- 找出全部DEPT_ID等於當前記錄PARENT_ID的記錄
START WITH DEPT_ID = 4               -- 從部門4開始遞歸查詢。
;
DEPT_ID    PARENT_ID DEPT_NAME AMOUNT
---------- --------- ---------- ------
4                  2 1-2-4          10
2                1 1-2            15
    1                1               2

三、部門1的全部下級部門。
SELECT LPAD(' ',2*(LEVEL - 1), ' ')||DEPT_ID AS DEPT_ID,
       PARENT_ID,DEPT_NAME,AMOUNT
FROM T_DEPT_TEMP
START WITH DEPT_ID = 1
CONNECT BY PARENT_ID = PRIOR DEPT_ID;
DEPT_ID    PARENT_ID DEPT_NAME AMOUNT
---------- --------- ---------- ------
1                    1               2
2                1 1-2            15
    4              2 1-2-4          10
    5              2 1-2-5           9
3                1 1-3             8
    6              3 1-3-6          17
    7              3 1-3-7           5
    8              3 1-3-8           6

四、部門1及其全部下級部門,可是不包括部門3及其下級部門。(排除樹枝)
SELECT LPAD(' ',2*(LEVEL - 1), ' ')||DEPT_ID AS DEPT_ID,
       PARENT_ID,DEPT_NAME,AMOUNT
FROM T_DEPT_TEMP
START WITH DEPT_ID = 1
CONNECT BY PARENT_ID = PRIOR DEPT_ID
         AND DEPT_ID <> 3    -- 不包括部門3及其下屬部門(部門3和六、七、8都沒出現)
;
DEPT_ID    PARENT_ID DEPT_NAME AMOUNT
---------- --------- ---------- ------
1                    1               2
2                1 1-2            15
    4              2 1-2-4          10
    5              2 1-2-5           9

五、部門1及其全部下級部門,可是僅不包括部門3。(排除節點)
SELECT LPAD(' ',2*(LEVEL - 1), ' ')||DEPT_ID AS DEPT_ID,
       PARENT_ID,DEPT_NAME,AMOUNT
FROM T_DEPT_TEMP
WHERE DEPT_ID <>3          -- 僅僅不包括部門3(輸出結果中,3的下級部門六、七、8仍是出現了)
START WITH DEPT_ID = 1
CONNECT BY PARENT_ID = PRIOR DEPT_ID -- 執行順序where在connect by以後
;
DEPT_ID    PARENT_ID DEPT_NAME AMOUNT
---------- --------- ---------- ------
1                    1               2
2                1 1-2            15
    4              2 1-2-4          10
    5              2 1-2-5           9
    6              3 1-3-6          17
    7              3 1-3-7           5
    8              3 1-3-8           6

六、部門1及其全部下級部門,且全部部門按照人數升序排列。
SELECT LPAD(' ',2*(LEVEL - 1), ' ')||DEPT_ID AS DEPT_ID,
       PARENT_ID,DEPT_NAME,AMOUNT
FROM T_DEPT_TEMP
START WITH DEPT_ID = 1
CONNECT BY PARENT_ID = PRIOR DEPT_ID
ORDER BY AMOUNT ASC -- 排序在最後被執行,因此DEPT_ID徹底被打亂了,並且層級關係也打亂了。
;
-- In a hierarchical query, do not specify either ORDER BY or GROUP BY, 
-- as they will destroy the hierarchical order of the CONNECT BY results.
DEPT_ID    PARENT_ID DEPT_NAME AMOUNT
---------- --------- ---------- ------
1                    1               2
    7              3 1-3-7           5
    8              3 1-3-8           6
3                1 1-3             8
    5              2 1-2-5           9
    4              2 1-2-4          10
2                1 1-2            15
    6              3 1-3-6          17

七、部門1及其全部下級部門,每一個部門的下一級部門之間,按照人數降序排列。(有同一上級的那些部門???
-- If you want to order rows of siblings of the same parent, 
-- then use the ORDER SIBLINGS BY clause.
SELECT LPAD(' ',2*(LEVEL - 1), ' ')||DEPT_ID AS DEPT_ID,
       PARENT_ID,DEPT_NAME,AMOUNT
FROM T_DEPT_TEMP
START WITH DEPT_ID = 1
CONNECT BY PARENT_ID = PRIOR DEPT_ID
ORDER SIBLINGS BY AMOUNT ASC -- 同屬部門間排序

-- 輸出結果可見,部門三、2做爲一組進行排序,部門七、八、6一組,五、4一組。
DEPT_ID    PARENT_ID DEPT_NAME AMOUNT
---------- --------- ---------- ------
1                    1               2
3                1 1-3             8
    7              3 1-3-7           5
    8              3 1-3-8           6
    6              3 1-3-6          17
2                1 1-2            15
    5              2 1-2-5           9
    4              2 1-2-4          10

3、要點總結
一、子句的語法書寫順序。
select -> from -> where -> start with -> connect by -> order by
where寫在connect by後面就不行,報錯。

二、子句的執行順序
from -> start with -> connect by -> where -> select -> order by
執行順序where在connect by以後,能夠從例5證實。
但是書寫SQL語句的時候,卻只能寫前面,注意理解。

三、如何理解和記憶「CONNECT BY PRIOR PARENT_ID = DEPT_ID 」的含義呢?
如今看這個例子彷佛很直觀,可是從此實際應用時,條件變化後,如何推斷查詢結果呢?
    這裏我本身總結一種方法,前提是要理解SQL語句執行時,是一條一條記錄來處理的。
每條知足START WITH語句條件的記錄被依次取出,暫且把每次被取出處理的記錄,稱爲當前記錄。
「PRIOR PARENT_ID」代表從當前記錄獲得PARENT_ID,
而後" = DEPT_ID"說明找到表中全部DEPT_ID等於當前記錄PARENT_ID的記錄,也就是找當前記錄PARENT_ID所指向的記錄。
    由於PARENT_ID的取值含義是上級節點,因此說明是向樹的根節點方向的搜索。(個人上級是誰?)
    反之,若是是「CONNECT BY PARENT_ID = PRIOR DEPT_ID」,「PRIOR」在DEPT_ID一邊,就是找全部PARENT_ID等於當前記錄DEPT_ID的記錄,是向樹的葉子方向的搜索。(誰的上級是我?)
    找到結果記錄集之後,從第一條記錄開始遞歸處理,依此類推。

四、前序遍歷
因爲是遞歸處理,從例3能夠看出,樹的根節點向葉子節點遞歸查詢時,查詢節點的順序是按照樹的前序遍歷進行的。

五、排序
例6和例7說明了兩種排序的區別。
In a hierarchical query, do not specify either ORDER 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.

六、僞列LEVEL
只能隨CONNECT BY子句一塊兒使用,是一個整數,表明遞歸的層次深度。也就是節點在樹中所處深度。
根節點時等於1,根節點的葉子節點的深度等於2,依此類推。
LPAD(' ',2*(LEVEL - 1), ' ')||DEPT_ID 正是利用了LEVEL來爲每一個層級的字段提供不一樣的縮進。


over

 

 

----btw  能夠理解爲從新排序。

相關文章
相關標籤/搜索