a我考网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 138|回复: 2

[综合] Oracle辅导:Oracle中10g树形查询新特性

[复制链接]
发表于 2012-8-4 13:54:49 | 显示全部楼层 |阅读模式
在10g中Oracle提供了新的伪列:CONNECT_BY_ISCYCLE,通过这个伪列,可以判断是否在树形查询的过程中构成了循环,这个伪列只是在CONNECT BY NOCYCLE方式下有效。   这一篇描述一下解决问题的思路。& o/ T; B" C1 t& p" T+ M5 V5 l4 A
  CONNECT_BY_ISCYCLE的实现和前面两篇文章中CONNECT_BY_ROOT和CONNECT_BY_ISLEAF的实现完全不同。1 a  y* [" N* S/ W% r% H* U
  因为要实现CONNECT_BY_ISCYCLE,就必须先实现CONNECT BY NOCYCLE,而在9i中是没有方法实现这个功能的。! W$ [0 G/ j- L
  也就是说,首先要实现自己的树形查询的功能,而仅这第一点,就是一个异常困难的问题,何况后面还要实现NOCYCLE,最后再加上一个ISCYCLE的判断。0 m. Q0 E0 e! ?9 y8 k# p; r2 `1 a
  所以总的来说,这个功能的实现比前面两个功能要复杂得多。由于树形查询的LEVEL是不固定的,所以采用链接的方式实现,基本上是不现实的。换句话说,用纯SQL的方式来实现树形查询的功能基本上不可行。而为了解决这个功能,只能通过PL/SQL配合SQL来实现。
+ u# }+ R* y  K  仍然是首先构造一个例子:8 F+ W/ _9 j& q, H1 N
  SQL> CREATE TABLE T_TREE (ID NUMBER, FATHER_ID NUMBER, NAME VARCHAR2(30));0 A" n  I3 ?. L
  表已创建。% a0 ?  `5 Y7 f" H) G4 q! k
  SQL> INSERT INTO T_TREE VALUES (1, 0, 'A');
. Y  i$ z' N9 w5 h0 _. \  已创建 1 行。
8 z) D7 R' c8 d3 Z/ t  SQL> INSERT INTO T_TREE VALUES (2, 1, 'BC');: y, j. _7 U3 t
  已创建 1 行。: A% r5 X% `4 L* s5 Z6 d6 E' o( \
  SQL> INSERT INTO T_TREE VALUES (3, 1, 'DE');9 Y- r# L/ ?# A4 @
  已创建 1 行。
6 p  O/ @$ R* p4 T- N& E+ E  SQL> INSERT INTO T_TREE VALUES (4, 1, 'FG');# D; {! N; o+ B& t7 R, k
  已创建 1 行。$ M% B% A  T; g% A
  SQL> INSERT INTO T_TREE VALUES (5, 2, 'HIJ');4 I+ m, ]' Q( ?$ L1 I$ B
  已创建 1 行。2 x9 Z& @* V5 D7 u
  SQL> INSERT INTO T_TREE VALUES (6, 4, 'KLM');
6 T0 Q1 k; n6 c: u; m  \  已创建 1 行。& P) `" g* z" Z) b# ^
  SQL> INSERT INTO T_TREE VALUES (7, 6, 'NOPQ');
( M3 e5 Z' ^+ ~0 s. n, L& E  已创建 1 行。+ i4 q% ~# v9 d$ ?& |) i' N4 D- [' y
  SQL> INSERT INTO T_TREE VALUES (0, 0, 'ROOT');) w! b/ y, z6 L6 G- }6 H2 S4 G
  已创建 1 行。, [5 u- `5 l1 p& R
  SQL> INSERT INTO T_TREE VALUES (4, 7, 'FG');
7 o( S% S$ w; s+ q  已创建 1 行。' L! B4 G* P8 Q6 S
  SQL> COMMIT;
4 o2 T1 g4 ^; V( B  提交完成。
. @, ~6 p5 X! V) q  SQL> SELECT * FROM T_TREE;
$ y0 ^/ L7 u. [* U  ID FATHER_ID NAME
+ }: n; _6 Y' C  ---------- ---------- ------------------------------4 G: C$ x$ m9 w! c5 Z
  1 0 A
1 @; Q7 b* B4 c. \1 L$ u  2 1 BC
2 M% `" c5 D2 ^/ O( _$ @) z  3 1 DE
! P2 D  w2 Y% ?4 G( p8 n! u  4 1 FG
8 p7 G9 u( `4 k( U  5 2 HIJ
* O3 O3 u$ ?% F# O  6 4 KLM; ]: o! e4 g# }5 f$ o3 N
  7 6 NOPQ2 Z7 b  L1 |8 b1 H1 [% a; Y1 I% F$ _
  0 0 ROOT
- F" j0 {. D: F/ @! z- v2 X  4 7 FG
& n& S& {* J. Z8 w' ^
$ x9 Q* m' x' G8 i  {" W  已选择9行。
回复

使用道具 举报

 楼主| 发表于 2012-8-4 13:54:50 | 显示全部楼层

Oracle辅导:Oracle中10g树形查询新特性

</p>  上面构造了两种树形查询循环的情况,一种是当前记录的自循环,另一种是树形查询的某个子节点是当前节点的祖先节点,从而构成了循环。在这个例子中,记录ID为0和ID为4且FATHER_ID等于7的两条记录分别构成了上述的两种循环的情况。0 F: r8 s, ~. E/ P4 @9 Z8 u+ }- R
  下面就来看看CONNECT_BY_ISCYCLE和CONNECT BY NOCYCLE的功能:
/ R8 |, V6 P! C7 e$ r+ S# q$ p  SQL> SELECT *8 h* F/ i' @. O
  2 FROM T_TREE
7 u# y& W) I1 {5 q  3 START WITH ID = 0  g3 l. X% [; Z! P
  4 CONNECT BY PRIOR ID = FATHER_ID;$ u; ]/ g- c( J( G/ H& }
  ERROR:( E, a0 G! S) T  n
  ORA-01436: 用户数据中的 CONNECT BY 循环
0 \- o; a* p' p) H) f3 C  未选定行) W# P/ w0 C5 X" R1 A
  SQL> SELECT *1 R4 X7 d( g0 \/ k7 }
  2 FROM T_TREE
1 V! C* s' e& `7 C* U7 p! L* H  3 START WITH ID = 1. K% X/ j3 c9 i6 b$ c+ S. {3 ^
  4 CONNECT BY PRIOR ID = FATHER_ID;- s  H9 A) }+ L* Z& l
  ERROR:+ \& z! R" F! v7 V+ J) H+ ]5 m
  ORA-01436: 用户数据中的 CONNECT BY 循环* n. p0 y  q; w* T' W+ T: s: K* p4 @
  未选定行* G  m  H" W; l1 X1 k) o
  这就是不使用CONNECT BY NOCYCLE的情况,查询会报错,指出树形查询中出现循环,在10g中可以使用CONNECT BY NOCYCLE的方式来避免错误的产生:
; c$ \5 B+ q, e& O' S  SQL> SELECT *
* D# X9 O: z( c+ Y# Y9 ?  2 FROM T_TREE
: T! A* T8 b  @! H, l2 [  3 START WITH ID = 0% g  w' ]9 s0 R8 c2 n
  4 CONNECT BY NOCYCLE PRIOR ID = FATHER_ID;+ I4 T$ w. M9 A2 ]1 B! u) @
  ID FATHER_ID NAME( H% x0 r4 K7 L. ]
  ---------- ---------- ------------------------------
: e" X) l4 Z* Q$ K& n- M4 l  0 0 ROOT
* Z9 [! [+ V0 e2 W6 D; M% Z  1 0 A
6 {# g1 Q* _, K* L1 ^  2 1 BC
- T0 [% Q! ^4 q* @( v' u! i# i& D# ?  5 2 HIJ
; i1 e* [7 z& y7 D. y  3 1 DE
; A8 M& ?7 }6 g# q- y, d  4 1 FG# x' A6 ]2 Y2 a% {
  6 4 KLM6 ^+ `' C, ]# i6 P4 h" q
  7 6 NOPQ9 l. r3 k8 x0 V' Y* d0 l
  已选择8行。
7 r" K' C4 U8 c2 x2 H3 q  使用CONNECT BY NOCYCLE,Oracle自动避免循环的产生,将不产生循环的数据查询出来,下面看看CONNECT_BY_ISCYCLE的功能:
' r  F/ j+ _# ]: k3 n& g4 `/ a6 E  SQL> SELECT ID,
2 M. C, x; S( l  2 FATHER_ID,) s' M' S/ \) s: x
  3 NAME,
3 {) G5 b, V  C  f3 Q- M  4 CONNECT_BY_ISCYCLE CYCLED. q; H. w5 ]. @! Q9 F3 ^2 l8 ]. R
  5 FROM T_TREE
; t) ^& I( A* \, e  6 START WITH ID = 0
: Y1 o) ?9 q" [* G. ~- v  7 CONNECT BY NOCYCLE PRIOR ID = FATHER_ID;
2 w5 p# g7 X5 u2 |* ]6 n  ID FATHER_ID NAME CYCLED
  d; H  K9 ^4 d: _) U+ S7 p  ---------- ---------- ------------------------------ ----------
+ |3 Z2 E5 X) c  0 0 ROOT 1
1 b, x1 @9 X" @! ~/ w" p  1 0 A 0
/ X% C* D' b$ r0 x9 U9 X  2 1 BC 0* S# A$ Q- G6 k9 B, E/ G: l
  5 2 HIJ 0
3 a4 U, h" T9 u  L/ W  3 1 DE 0, F& b  D7 Z. b
  4 1 FG 0
1 Z' p5 L, R" R. q  6 4 KLM 08 s4 R' k9 k9 T. V3 s
  7 6 NOPQ 1) q% ~# Q! h; {, [4 w; o9 w/ X3 I
  已选择8行。
7 U. u* u+ l( H2 l1 w; k
. [: P: X! D2 _' }: b0 Z! m  可以看到,CONNECT_BY_ISCYCLE伪列指出循环在树形查询中发生的位置。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-8-4 13:54:51 | 显示全部楼层

Oracle辅导:Oracle中10g树形查询新特性

</p>  为了实现CONNECT_BY_ISCYCLE就必须先实现CONNECT BY NOCYCLE方式,而这在9i中是没有现成的办法的,所以这里尝试使用PL/SQL来自己实现树形查询的功能。6 e3 Y6 ^7 G: z3 m7 j8 F. N& n, D
  SQL> CREATE OR REPLACE FUNCTION F_FIND_CHILD(P_VALUE VARCHAR2) RETURN VARCHAR2 AS
- e2 c: s% P: A; q2 Q( \6 l  2 V_STR VARCHAR2(32767) := '/' || P_VALUE;  x+ K  S" J& q7 S0 @" q) L" _, G
  3
- D5 S- u$ ?7 k  4 PROCEDURE P_GET_CHILD_STR (P_FATHER IN VARCHAR2, P_STR IN OUT VARCHAR2) AS
  m/ `' N- R8 C  5 BEGIN- K- L4 K: k- ^' ~
  6 FOR I IN (SELECT ID FROM T_TREE WHERE FATHER_ID = P_FATHER AND FATHER_ID != ID) LOOP
4 d6 w9 v# C1 G; [) r% y& T3 W  v9 }. Q  7 IF INSTR(P_STR || '/', '/' || I.ID || '/') = 0 THEN
# n; q: u$ d/ m- M- W  8 P_STR := P_STR || '/' || I.ID;2 z9 F; D! O4 L5 U# e( K
  9 P_GET_CHILD_STR(I.ID, P_STR);# l/ L; Y* d3 I3 [2 H6 {1 i4 a
  10 END IF;8 H+ c5 @, t$ P- R: L5 r6 H6 ~
  11 END LOOP;1 z- q" S; {$ O
  12 END;% P9 M4 s: @5 x# `
  13 BEGIN7 t; ~) |, y; y: t, y* `
  14 P_GET_CHILD_STR(P_VALUE, V_STR);
0 [1 s* A! d' D& b! R  15 RETURN V_STR;
/ Q" W- T* t& Y& K, e/ L  16 END;
7 o" i7 X' B6 ~) h: C: u  17 /9 c' u4 g$ j. a
  函数已创建。' s: f3 V' h3 |9 R5 Z  `9 a9 R. P2 S
  构造一个函数,在函数中递归调用过程来实现树形查询的功能。  s! o/ P" p8 \1 q8 z3 _  n' J
  下面看看调用这个函数的结果:- ?4 J( g: h, X, Z! }% i
  SQL> SELECT F_FIND_CHILD(0) FROM DUAL;2 p# u' ~: W+ i3 a# G7 ~$ y
  F_FIND_CHILD(0)
: a( f: w6 o) g  ------------------------------------------------0 j3 ~# \# [( A4 j  @7 B
  /0/1/2/5/3/4/6/7
; o0 L( \' r" S* _9 H  SQL> SELECT F_FIND_CHILD(2) FROM DUAL;3 x# \1 S0 C, D& g) L' T/ C
  F_FIND_CHILD(2)
% ?6 ?% b6 G! h1 u7 r: N- V  ------------------------------------------------
) T# i7 e! N9 ~$ W+ _9 L  /2/5
! W  s( G$ D  T* d  SQL> SELECT F_FIND_CHILD(4) FROM DUAL;
( [) Z  o* W! _  F_FIND_CHILD(4)1 j7 d- m/ P) c  x% F" h/ S' w  B& C
  ------------------------------------------------
  Q; v, c: c. S6 q  L5 [# S5 [  /4/6/7
" e7 z, [' x# `  虽然目前存在的问题还有很多,但是已经基本上实现了一个最简单的NOCYCLE的SYS_CONNECT_BY_PATH的功能。* x9 V$ _2 m' Y4 }2 U7 a
  有了这个函数作为基础,就可以逐步的实现最终的目标了。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Woexam.Com ( 湘ICP备18023104号 )

GMT+8, 2024-5-21 10:39 , Processed in 0.150550 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表