內容來自:http://www.cnblogs.com/baiyixianzi/archive/2012/08/30/plsql12.html 和 http://jingyan.baidu.com/article/5d368d1e182bb93f60c05784.html
這里留個備份,方便以后查看。
一、語法
大致寫法:select * from some_table [where 條件1] connect by [條件2] start with [條件3];
其中 connect by 與 start with 語句擺放的先后順序不影響查詢的結果,[where 條件1]可以不需要。
[where 條件1]、[條件2]、[條件3]各自作用的范圍都不相同:
[where 條件1]是在根據“connect by [條件2] start with [條件3]”選擇出來的記錄中進行過濾,是針對單條記錄的過濾, 不會考慮樹的結構;
[條件2]指定構造樹的條件,以及對樹分支的過濾條件,在這里執行的過濾會把符合條件的記錄及其下的所有子節點都過濾掉;
[條件3]限定作為搜索起始點的條件,如果是自上而下的搜索則是限定作為根節點的條件,如果是自下而上的搜索則是限定作為葉子節點的條件;
示例:
假如有如下結構的表:some_table(id,p_id,name),其中p_id保存父記錄的id。
select * from some_table t where t.id!=123 connect by prior t.p_id=t.id and t.p_id!=321 start with t.p_id=33 or t.p_id=66;
對prior的說明:
prior存在於[條件2]中,可以不要,不要的時候只能查找到符合“start with [條件3]”的記錄,不會在尋找這些記錄的子節點。要的時候有兩種寫法:connect by prior t.p_id=t.id 或 connect by t.p_id=prior t.id,前一種寫法表示采用自上而下的搜索方式(先找父節點然后找子節點),后一種寫法表示采用自下而上的搜索方式(先找葉子節點然后找父節點)。
二、執行原理
connect by...start with...的執行原理可以用以下一段程序的執行以及對存儲過程RECURSE()的調用來說明:
/* 遍歷表中的每條記錄,對比是否滿足start with后的條件,如果不滿足則繼續下一條,
如果滿足則以該記錄為根節點,然后調用RECURSE()遞歸尋找該節點下的子節點,
如此循環直到遍歷完整個表的所有記錄 。*/
for rec in (select * from some_table) loop
if FULLFILLS_START_WITH_CONDITION(rec) then
RECURSE(rec, rec.child);
end if;
end loop;
/* 尋找子節點的存儲過程*/
procedure RECURSE (rec in MATCHES_SELECT_STMT, new_parent IN field_type) is
begin
APPEND_RESULT_LIST(rec); /*把記錄加入結果集合中*/
/*再次遍歷表中的所有記錄,對比是否滿足connect by后的條件,如果不滿足則繼續下一條,
如果滿足則再以該記錄為根節點,然后調用RECURSE()繼續遞歸尋找該節點下的子節點,
如此循環直到找至葉子節點。*/
for rec_recurse in (select * from some_table) loop
if FULLFILLS_CONNECT_BY_CONDITION(rec_recurse.child, new_parent) then
RECURSE(rec_recurse,rec_recurse.child);
end if;
end loop;
end procedure RECURSE;
三、使用探討
從上面的執行原理可以看到“connect by...start with...”構造樹的方式是:(1)如果是自上而下方式,則把表中的每一條記錄都作為根節點來生成樹,所以表中有多少條記錄就會構造出多少棵樹。(2)如果是自下而上的搜索方式,則把表中的每一條記錄都作為葉子節點來生成分支,所以表中有多少條記錄就會生成多少條分支。
因此如果表中的記錄不是嚴格遵照每條記錄都只能有一個父記錄的原則,那么就可能有部分記錄會存在於多棵樹中,那么在查找記錄的時候就可能會出現找到多條重復記錄的異常情況
--1.Hierarchical Queries: START WITH and CONNECT BY PRIOR clauses
--Hierarchical Queries
--START WITH and CONNECT BY PRIOR clauses.
SELECT employee_id, manager_id, first_name, last_name
FROM employee_jh
START WITH employee_id = 1
CONNECT BY PRIOR employee_id = manager_id;
EMPLOYEE_ID MANAGER_ID FIRST_NAME LAST_NAME
----------- ---------- ---------- ----------
1 0 James Smith
2 1 Ron Johnson
3 2 Fred Hobbs
5 2 Rob Green
4 1 Susan Jones
6 4 Jane Brown
9 6 Henry Heyson
7 4 John Grey
8 7 Jean Blue
10 1 Kevin Black
11 10 Keith Long
12 10 Frank Howard
13 10 Doreen Penn
13 rows selected.
--2.Using a Subquery in a START WITH Clause
SELECT LEVEL,
LPAD(' ', 2 * LEVEL - 1) || first_name || ' ' || last_name AS employee
FROM employee_jh
START WITH employee_id = (SELECT employee_id FROM employee_jh WHERE first_name = 'Kevin' AND last_name = 'Black')
CONNECT BY PRIOR employee_id = manager_id;
LEVEL EMPLOYEE
---------- -------------------------
1 Kevin Black
2 Keith Long
2 Frank Howard
2 Doreen Penn
--3.Including Other Conditions in a Hierarchical Query
SELECT LEVEL,
LPAD(' ', 2 * LEVEL - 1) || first_name || ' ' ||
last_name AS employee, salary
FROM employee_jh
WHERE salary <= 50000
START WITH employee_id = 1
CONNECT BY PRIOR employee_id = manager_id;
LEVEL EMPLOYEE SALARY
---------- ------------------------- ----------
3 Rob Green 40000
3 Jane Brown 45000
4 Henry Heyson 30000
3 John Grey 30000
4 Jean Blue 29000
3 Keith Long 50000
3 Frank Howard 45000
3 Doreen Penn 47000
8 rows selected.
select num1,num2,level
from carol_tmp
start with num2=1008
connect by num2=prior num1 order by level desc;
prior放的左右位置決定了檢索是自底向上還是自頂向下.很明顯以上的sql選擇了自底向上,所以最終得到了根節點。

select num1,num2,level
from carol_tmp
start with num2=1008
connect by prior num2= num1 order by level desc;
這次prior和num2放在了一起,他意思就是從num2開始尋找其下面最小的葉節點。

--取所有下級(含自己)
select depot_id, --編號
depot_parent_id --父級編號
from table1 a
where a.sys_type=1
start with a.depot_id=v_depot_id --參數,傳入當前級別,查詢所有下級(含自己)
connect by nocycle prior a.depot_id=a.depot_parent_id;