我申请这个blog是为了督促自己,把自己平时的一些想法和思考结果保留下来。 本博客所有内容均为原创,如有转载请注明作者和出处

10g树形查询新特性CONNECT_BY_ISCYCLE的9i实现方式(一)

上一篇 / 下一篇  2008-07-20 23:56:28 / 个人分类:ORACLE

10gOracle提供了新的伪列:CONNECT_BY_ISCYCLE,通过这个伪列,可以判断是否在树形查询的过程中构成了循环,这个伪列只是在CONNECT BY NOCYCLE方式下有效。

这一篇描述一下解决问题的思路。

 

 

CONNECT_BY_ISCYCLE的实现和前面两篇文章中CONNECT_BY_ROOTCONNECT_BY_ISLEAF的实现完全不同。

因为要实现CONNECT_BY_ISCYCLE,就必须先实现CONNECT BY NOCYCLE,而在9i中是没有方法实现这个功能的。

也就是说,首先要实现自己的树形查询的功能,而仅这第一点,就是一个异常困难的问题,何况后面还要实现NOCYCLE,最后再加上一个ISCYCLE的判断。

所以总的来说,这个功能的实现比前面两个功能要复杂得多。由于树形查询的LEVEL是不固定的,所以采用链接的方式实现,基本上是不现实的。换句话说,用纯SQL的方式来实现树形查询的功能基本上不可行。而为了解决这个功能,只能通过PL/SQL配合SQL来实现。

仍然是首先构造一个例子:

SQL> CREATE TABLE T_TREE (ID NUMBER, FATHER_ID NUMBER, NAME VARCHAR2(30));

表已创建。

SQL> INSERT INTO T_TREE VALUES (1, 0, 'A');

已创建1行。

SQL> INSERT INTO T_TREE VALUES (2, 1, 'BC');

已创建1行。

SQL> INSERT INTO T_TREE VALUES (3, 1, 'DE');

已创建1行。

SQL> INSERT INTO T_TREE VALUES (4, 1, 'FG');

已创建1行。

SQL> INSERT INTO T_TREE VALUES (5, 2, 'HIJ');

已创建1行。

SQL> INSERT INTO T_TREE VALUES (6, 4, 'KLM');

已创建1行。

SQL> INSERT INTO T_TREE VALUES (7, 6, 'NOPQ');

已创建1行。

SQL> INSERT INTO T_TREE VALUES (0, 0, 'ROOT');

已创建1行。

SQL> INSERT INTO T_TREE VALUES (4, 7, 'FG');

已创建1行。

SQL> COMMIT;

提交完成。

SQL> SELECT * FROM T_TREE;

        ID  FATHER_ID NAME
ea@uO"[0---------- ---------- ------------------------------ITPUB个人空间-@KP!hq;[4`/P
         1         0 AITPUB个人空间_ _:_cV%LwM
         2          1 BC
eB J p1Z1d?t1ME0         3          1 DEITPUB个人空间 l/y0J bD
         4          1 FG
"s!iP3a5UT!G/R0         5          2 HIJ
8C(LK;x+k?j0         6          4 KLMITPUB个人空间P;T*En9c
         7          6 NOPQ
"@"Y"l8Ml0         0          0 ROOTITPUB个人空间4^'cWy4sK
         4          7 FG

已选择9行。

上面构造了两种树形查询循环的情况,一种是当前记录的自循环,另一种是树形查询的某个子节点是当前节点的祖先节点,从而构成了循环。在这个例子中,记录ID0ID4FATHER_ID等于7的两条记录分别构成了上述的两种循环的情况。

下面就来看看CONNECT_BY_ISCYCLECONNECT BY NOCYCLE的功能:

SQL> SELECT *
+V%U'k6b |3mT ~;PBx"F0  2  FROM T_TREE
%b Q*y"D}/Z$W;M0  3  START WITH ID = 0ITPUB个人空间V"bO:L} u~2MOP[
  4  CONNECT BY PRIOR ID = FATHER_ID;
'cV4E Z \kd0ERROR:
Ns3mGN0k;zS0x `0ORA-01436:
用户数据中的CONNECT BY循环

 

未选定行

SQL> SELECT *
#_1@3|KrD0  2  FROM T_TREEITPUB个人空间1}D1siK2fZ CS:J
  3  START WITH ID = 1
y A8e yb&M0  4  CONNECT BY PRIOR ID = FATHER_ID;ITPUB个人空间1{8a{"O `8C k
ERROR:ITPUB个人空间 M6\!R:p.qe
ORA-01436:
用户数据中的CONNECT BY循环

 

未选定行

这就是不使用CONNECT BY NOCYCLE的情况,查询会报错,指出树形查询中出现循环,在10g中可以使用CONNECT BY NOCYCLE的方式来避免错误的产生:

SQL> SELECT *ITPUB个人空间-Tpg [U@"s
  2  FROM T_TREEITPUB个人空间.e0QP&e@o
  3  START WITH ID = 0
U:` RX*yR6a0  4  CONNECT BY NOCYCLE PRIOR ID = FATHER_ID;

        ID  FATHER_ID NAME
8y5s`'|%|zH!yZ0---------- ---------- ------------------------------
\a1bbHI0         0          0 ROOTITPUB个人空间gh)GB Q
         1         0 A
d MY:p1h#M0         2          1 BCITPUB个人空间)ApsRK:J7{Ir-z,j
         5          2 HIJ
-t @h%B3]N UH%w;w0         3          1 DE
:NWD Zq|u0         4          1 FG
U8iL%K-xdz1jG0         6          4 KLM
`'g$g$XBu0         7          6 NOPQ

已选择8行。

使用CONNECT BY NOCYCLEOracle自动避免循环的产生,将不产生循环的数据查询出来,下面看看CONNECT_BY_ISCYCLE的功能:

SQL> SELECT ID,ITPUB个人空间+EAG*Q,m%D{V
  2  FATHER_ID,ITPUB个人空间\b l,U+gQ*qg(i
  3  NAME,ITPUB个人空间 ]5yM(o'x
  4  CONNECT_BY_ISCYCLE CYCLED
A2R2L/b$~4k0  5  FROM T_TREEITPUB个人空间tE6B'WUv @k
  6  START WITH ID = 0ITPUB个人空间%y.rv'j3[)u
  7  CONNECT BY NOCYCLE PRIOR ID = FATHER_ID;

        ID  FATHER_ID NAME                               CYCLED
!W/q!vu7?#Yc8y0---------- ---------- ------------------------------ ----------ITPUB个人空间)a vzt {q"@wm
         0          0 ROOT                                    1
)|#vzjVn `&`0         1         0 A                                       0
I}%d#xT"A.x5q0         2          1 BC                                      0ITPUB个人空间Z c[ QA7q5Mt;y.T
         5          2 HIJ                                     0
3yI5gu8@C0         3          1 DE                                      0ITPUB个人空间-t$X_,Gk
         4          1 FG                                      0
Jw3X{m&d m0         6          4 KLM                                     0
1y~-Qr,lhc0         7          6 NOPQ                                    1

已选择8行。

可以看到,CONNECT_BY_ISCYCLE伪列指出循环在树形查询中发生的位置。

为了实现CONNECT_BY_ISCYCLE就必须先实现CONNECT BY NOCYCLE方式,而这在9i中是没有现成的办法的,所以这里尝试使用PL/SQL来自己实现树形查询的功能。

SQL> CREATE OR REPLACE FUNCTION F_FIND_CHILD(P_VALUE VARCHAR2) RETURN VARCHAR2 ASITPUB个人空间I@#g-N$v/O
  2   V_STR VARCHAR2(32767) := '/' || P_VALUE;ITPUB个人空间Lo;x'GUzl
  3 
6\q%rRcI,}0  4   PROCEDURE P_GET_CHILD_STR (P_FATHER IN VARCHAR2, P_STR IN OUT VARCHAR2) AS
1BGC,?5}:s\*S8^0  5   BEGIN
H@n7y n;@0  6    FOR I IN (SELECT ID FROM T_TREE WHERE FATHER_ID = P_FATHER AND FATHER_ID != ID) LOOPITPUB个人空间^;zp8i3j$Wp+~9C
  7     IF INSTR(P_STR || '/', '/' || I.ID || '/') = 0 THEN
:raG4j Um]0\0  8      P_STR  := P_STR || '/' || I.ID;
,Y0q1A;J#TX0  9      P_GET_CHILD_STR(I.ID, P_STR);
9i\%Cnn)RVE#H0 10     END IF;
-w ^lL](e]0 11    END LOOP;ITPUB个人空间+paw#]*xp~M
 12   END;
T7py\g"yU2I1M0 13  BEGIN
E^1R!H$D/`0 14   P_GET_CHILD_STR(P_VALUE, V_STR);ITPUB个人空间XIi`JxnR
 15   RETURN V_STR;ITPUB个人空间Pr ]}5h(c-a(^
 16  END;
_5zqGm8j$F t@|0 17  /

函数已创建。

构造一个函数,在函数中递归调用过程来实现树形查询的功能。

下面看看调用这个函数的结果:

SQL> SELECT F_FIND_CHILD(0) FROM DUAL;

F_FIND_CHILD(0)
q{Xt#i8U%]8^t1t ]0------------------------------------------------
:~2v#vq \ jm0/0/1/2/5/3/4/6/7

SQL> SELECT F_FIND_CHILD(2) FROM DUAL;

F_FIND_CHILD(2)ITPUB个人空间 lzEO s,`J9m
------------------------------------------------
'^X0C-BR#CF]0/2/5

SQL> SELECT F_FIND_CHILD(4) FROM DUAL;

F_FIND_CHILD(4)
N!Avc|&yYo+GR2u0------------------------------------------------
"z)^ qpS ? XvZ0/4/6/7

虽然目前存在的问题还有很多,但是已经基本上实现了一个最简单的NOCYCLESYS_CONNECT_BY_PATH的功能。

有了这个函数作为基础,就可以逐步的实现最终的目标了。

 


TAG:

 

评分:0

我来说两句

显示全部

:loveliness: :handshake :victory: :funk: :time: :kiss: :call: :hug: :lol :'( :Q :L ;P :$ :P :o :@ :D :( :)

Open Toolbar