【層次查詢】Hierarchical Queries之處理順序

secooler發表於2010-01-04
有關層次查詢之前的文章參考如下。
【層次查詢】Hierarchical Queries之“樹的遍歷”
http://space.itpub.net/519536/viewspace-623809
【層次查詢】Hierarchical Queries之LEVEL應用
http://space.itpub.net/519536/viewspace-623916
【層次查詢】Hierarchical Queries之CONNECT_BY_ISCYCLE偽列
http://space.itpub.net/519536/viewspace-624032
【層次查詢】Hierarchical Queries之CONNECT_BY_ISLEAF偽列
http://space.itpub.net/519536/viewspace-624075
【層次查詢】Hierarchical Queries之SYS_CONNECT_BY_PATH函式
http://space.itpub.net/519536/viewspace-624099
【層次查詢】Hierarchical Queries之尋根問祖(CONNECT_BY_ROOT一元運算子)
http://space.itpub.net/519536/viewspace-624114
【層次查詢】Hierarchical Queries之親兄弟間的排序(ORDER SIBLINGS BY)
http://space.itpub.net/519536/viewspace-624176

如若對層次查詢中的諸多條件的處理順序不清楚的話,在某些情況下可能會得到一些意想不到的資料結果,理解層次查詢的處理順序刻不容緩。
本文會先給出一個容易誤解的例子,然後會給出層次查詢處理順序的一般原則。

1.回望關係“樹”,注意力請集中在第三層的D和E。
      A
     / \
    B   C
   /   /
  D   E
 / \
F   G

2.重溫一下闡述上圖的T表資料
sec@ora10g> select * from t;

X                   Y          Z
---------- ---------- ----------
A                   1
B                   2          1
C                   3          1
D                   4          2
E                   5          3
F                   6          4
G                   7          4

7 rows selected.

3.先看一下“level != 3”這個條件在where子句和connect by子句中各自的效果。後面會給出差異原因。
1)不加限制條件,以A為根節點的全貌如下。
sec@ora10g> col tree for a16
sec@ora10g> col tree_path for a16
sec@ora10g> select lpad(' ',level-1)||x tree, SYS_CONNECT_BY_PATH(x,'/') tree_path, level from t start with x = 'A' connect by prior y=z;

TREE             TREE_PATH             LEVEL
---------------- ---------------- ----------
A                /A                        1
 B               /A/B                      2
  D              /A/B/D                    3
   F             /A/B/D/F                  4
   G             /A/B/D/G                  4
 C               /A/C                      2
  E              /A/C/E                    3

7 rows selected.

2)條件“level != 3”在where子句時的效果
sec@ora10g> select lpad(' ',level-1)||x tree, SYS_CONNECT_BY_PATH(x,'/') tree_path, level from t where level != 3 start with x = 'A' connect by prior y=z;

TREE             TREE_PATH             LEVEL
---------------- ---------------- ----------
A                /A                        1
 B               /A/B                      2
   F             /A/B/D/F                  4
   G             /A/B/D/G                  4
 C               /A/C                      2

3)條件“level != 3”在connect by子句時的效果
sec@ora10g> select lpad(' ',level-1)||x tree, SYS_CONNECT_BY_PATH(x,'/') tree_path, level from t start with x = 'A' connect by prior y=z and level != 3;

TREE             TREE_PATH             LEVEL
---------------- ---------------- ----------
A                /A                        1
 B               /A/B                      2
 C               /A/C                      2

4)比較結果
當“level != 3”條件在where子句時,我們可以看到結果僅僅是將第三層的D和E過濾掉了。
然而,當“level != 3”條件在connect by子句時,我們發現第三層及其之後的節點資料全部被過濾掉了。

4.緣由--層次查詢的處理順序
根本原因在於層次查詢中的語句處理順序,包含層次查詢的SQL的處理順序如下:
首先處理:FROM和WHERE子句中連線條件
其次處理:START WITH子句
再次處理:CONNECT BY子句
最後處理:非連線條件的WHERE子句

本例中用到了後三種子句,因此當“level != 3”條件在where子句時,因為start with和connect by子句先被處理,因此整棵樹會先被構造出來,在這個樹的基礎上再處理where子句中的限制條件,所以結果僅僅去掉了第三層節點資料。
然而當條件“level != 3”在connect by子句時,由於先對connect by子句進行處理,導致第三層及之後的資料全部被過濾掉了,因此只剩下第一層和第二層的節點資料。

5.小結
深諳層析查詢的處理順序是得到正確查詢結果的前提,本文只是拋一小磚,點到為止,更多的收穫來自實踐的積累。

Good luck.

secooler
10.01.04

-- The End --



來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/519536/viewspace-624276/,如需轉載,請註明出處,否則將追究法律責任。

相關文章