天地不仁,以万物为刍狗!

[原]关于db2递归的一个例子

上一篇 / 下一篇  2008-03-14 13:58:12 / 个人分类:db2

关于db2递归的一个例子ITPUB个人空间1Z$o M.j Po

1V]pvtp6@%Z+T0ORACLE中大家可能对递归(在oracle中很多人称作家族树)已经很熟悉,因为ORACLE中的递归比较简单,也容易掌握!刚接触DB2的时候,也碰到过递归的问题,因为研究的人少所以刚接触的时候,对db2有一种神秘的感觉,db2是很强大的这个误用质疑!就sql而言,凡是oracle用sql能实现的,db2肯定或多或少也可以实现,只是逻辑复杂点!因为一直有人提问这边的问题,所以今天抽时间写了一点ITPUB个人空间H4u"G}Pr%Q0i$[
ITPUB个人空间6mWiHk _1VYM5Q
首先,关于db2的递归的一点基础知识:
j;c9]pT Q5m0
p4qF~%f J[0db2中的递归查询使用with来实现,也称为公共表达式,公共表达式在select语句的开始部分采用with子句的形式,在使用公共表达式的查询中可以多次使用它,并且公共表达式还可以通过取别名来连接到他本身,这样的话就可以达到循环的目的。ITPUB个人空间'hwUa0^Jo3r
ITPUB个人空间Zh9Fd~u_4Vr,SO p*?
递归查询通常有3个部分需要定义:ITPUB个人空间vp5x#gyT$fW\fVP
ITPUB个人空间9wz/K1hQ3s:J
一:一个公共表达式形式的虚拟表。ITPUB个人空间1RmC$K:P0\5jIfi
二:一个初始化表。
Q K8h.u*PwSPX0三:一个与虚拟表进行完全内连接的辅助表。
|'Rb)p%E0ITPUB个人空间kmix;q] ]
需要使用UNION all合并上边3个查询,然后用select从递归输出中得到最终的结果。ITPUB个人空间 Id+n/G%JN _2p

8D-OoCNb0大体上如下形式
!T#z:r!q8`\:x0with XX(x1,x2,x3) as  -------@0
E,{ `._L@0(
HU A8D|0select a.s,a.s1 from a  ----@1ITPUB个人空间!];n"cE9[:o
union all  ----@2ITPUB个人空间\r'YhtD
select * from a,xx where a.s=xx.x1 ------@3ITPUB个人空间]W!z}V
)ITPUB个人空间!x3N@ X E9^
select ... from xx where .... -------@4ITPUB个人空间%cYi:x2Nz?Q7[Y
ITPUB个人空间el'Zlt1J
@0:为with体,即虚拟表
R[1NE;N0@1:为初始化表,这里需要定义初始化的一些行,也就是你递归的出发点,或者说父行,这部分逻辑只执行一次,它的结果作为虚拟表递归的初始化内容。ITPUB个人空间)K!L5@&e*K$o
@2:这里必须用UNION all
*Qh0~k}pJ0@3:这里需要定义递归的条件(辅助表),这里定义递归的逻辑,需要注意的是父行和子行进行连接的时候逻辑一定要清楚父子关系,不然很容易变成死循环的,这里首先将初始化表的结果作为条件进行查询,在把执行的结果添加到虚拟表中,只要这里能查询出来记录,那么就会进行下一步递归循环。ITPUB个人空间0^ I})_!mB
@4:这里就是对虚拟表的查询语句。
1~8ih M1h p~0
Rek Thv0M0关于关于递归更多的知识,可以到google中找更专业的资料,这里只讲我理解的一些东西。
,@bBr-|Q0这里举一个简单点的例子:
BLh*H"},]8t(W9{0
@+v!s;^"t9A0-------------------------------
u;n Z?8N c d0Q:求一SQL--关于数据纵横转换的
8Oj*vNW0ITPUB个人空间Q@ Y{/T q
ITPUB个人空间5E5EV,n N-v7E
假设表A中有以下数据ITPUB个人空间,[~2],ZxRqPB
A1 1 01
9Xr0|IDH1j0A1 1 02ITPUB个人空间Xcl*PwSC3LqgD
A1 1 03ITPUB个人空间t\Z/X-?
A2 1 01ITPUB个人空间drWA7n1\7[
A2 2 01ITPUB个人空间(u$y,i;AxS!h#om]h
A2 2 02ITPUB个人空间4R*{.P2sU)u
现希望一SQL能够查出下边这样的数据(暂时假设表A中第三列只有01-03这三种可能值)
kb-w I1w0A1 1 01-02-03ITPUB个人空间'[Mr6l5B"z)H d6j
A2 1 01ITPUB个人空间*nz9p4c+vn E
A2 2 01-02
9GO.f M6VB2mdb,]~0ITPUB个人空间@2m3rz$gaO.s
A:这个查询牵扯到全表的递归循环,用一般的sql语句很难搞定!
w_ @5_(JUm'X0B0ITPUB个人空间*io)T`6r:M
这是我刚写的一个递归语句!分享给大家看看!
]!Y)G Zw;s0
-@o${ Q(NO9j,Y"jo0因为懒,所以把建立测试表的逻辑也略去了,这里用with来生成上边的测试数据。
-]2C$s J ZqY0with t (t1,t2,t3) as (
r3r0K%}1nf ?5Q0valuesITPUB个人空间$sww Y/CX3s
('A1', 1 ,'01'),('A1' ,1, '02'),('A1', 1, '03'),
XTN(m)md%s-I0('A2', 1, '01'),('A2', 2, '01'),('A2', 2 ,'02')
f0af@{ f0)
J.ZyXT$h"n0select * from t;
"x4T+Q|+m8t+wW0r6l0测试一下:ITPUB个人空间B"y.g-NG i;X
ITPUB个人空间2EKs$di!RkjXi
C:\>db2 connect to dwITPUB个人空间 V^^ iHxW+ag
ITPUB个人空间\)A4I2?Rlb?
   数据库连接信息
Oa5Dj7u0
e?*Rn4Ssc0数据库服务器         = DB2/NT 8.2.0ITPUB个人空间(_m%w4Y1C%|2C
SQL 授权标识         = DB2ADMIN
p/o8Uw+TM Mc0本地数据库别名       = DW
0A]6X1@ fkoZ0
!Q5S'A;YD f,X0ITPUB个人空间$F:}*SlI|%|
C:\>db2 with t (t1,t2,t3) as ( \ITPUB个人空间@C~vmB\'C o
db2 (cont.) => values \ITPUB个人空间:QK1O!k&VY{%S
db2 (cont.) => ('A1', 1 ,'01'),('A1' ,1, '02'),('A1', 1, '03'), \
J a5u[8Ow(a`r i0db2 (cont.) => ('A2', 1, '01'),('A2', 2, '01'),('A2', 2 ,'02') \
)g3jN4Ic&iCM8O0db2 (cont.) => ) \ITPUB个人空间-x*| zD'K`n5s.M7B
db2 (cont.) => select * from tITPUB个人空间 U A{A3D8q
ITPUB个人空间Y2z` dj|y
T1 T2          T3ITPUB个人空间W)x2Ss3Lqs(Sy
-- ----------- --
-uh AY;J'yw(YQ0A1           1 01ITPUB个人空间]g^$Q-N \@ x
A1           1 02ITPUB个人空间 ] `kA#S
A1           1 03
1gxhk3dL9~ Dw}9e0A2           1 01ITPUB个人空间 }(\j0a BhU F n
A2           2 01ITPUB个人空间~ ? w1aD@ g:nlyU
A2           2 02ITPUB个人空间:u5F7cK0x
ITPUB个人空间+Kv u?s |;^
  6 条记录已选择。ITPUB个人空间#mnWoB*f

Q{e+VH1R0ITPUB个人空间Qs B)ic.q8z
现在公布递归逻辑,sql如下:ITPUB个人空间/U+a gGN c"_0?-~.W
with t (t1,t2,t3) as (
*A4P| A~MY2w,{0valuesITPUB个人空间 x%L l {$~.k4w
('A1', 1 ,'01'),('A1' ,1, '02'),('A1', 1, '03'),ITPUB个人空间R\Fi ^r_
('A2', 1, '01'),('A2', 2, '01'),('A2', 2 ,'02')ITPUB个人空间(t$T-?.EvyI
),
%lt9g$Y!V0d"s%A'I0t1(t11,t22,t33,t44,t55) as (ITPUB个人空间qT-@$OT9^*p$B
select t1,t2,t3,rownumber() over(partition by t1,t2),rownumber() over(partition by t1,t2) as t4 from t
d-nO2gk-TS"w\0),ITPUB个人空间c F|a$bC sU!RU
t3(s1,s2,s3,s4,s5) as(ITPUB个人空间:u H8U;G h5}
select t11,t22,cast(t33 as varchar(100)),t44,t55 from t1 where T44 =1 and t55=1ITPUB个人空间 T}"n8gg G7t/C
union allITPUB个人空间7U Sk7]0B:h%C
select a.s1,a.s2,cast(a.s3||'-'||b.t33 as varchar(100)),a.s4+1,a.s5 from t3 a,t1 b
$Eo SA?\)V&y$M0where a.s1=b.t11 and a.s4 = b.t55-1)ITPUB个人空间q~ I#N[~!eZ
select s1,s2,s3 from t3 x where x.s4=(select max(s4) from t3 y where x.s1=y.s1) order by s1,s2
Rcu!Th9w/B%u&U#Z0;ITPUB个人空间sWJJv0S

&@zG9l&U@(g0测试一下:ITPUB个人空间f*Q*Wn*R7o

;pW%nQ)R D4f2S(O0
3O;Y%]8geQVh0C:\>db2 connect to dw
*wD*d8E'WB Yc{0ITPUB个人空间Gp_%a*z ^Ft:i
   数据库连接信息ITPUB个人空间7ehV HK.l L7` U
ITPUB个人空间9q!QN#b1QE$p
数据库服务器         = DB2/NT 8.2.0
TDW4H8OH.w R0SQL 授权标识         = DB2ADMIN
1Je;pC[7i0本地数据库别名       = DW
DT E&Q`&N b1E}0ITPUB个人空间\lA&d)Ps/`}

)?&zEa7t DYf0C:\>db2 with t (t1,t2,t3) as ( \
4Xl y2M#b0d0db2 (cont.) =>  values \ITPUB个人空间%eNl9~;J!@j(C
db2 (cont.) => ('A1', 1 ,'01'),('A1' ,1, '02'),('A1', 1, '03'), \
s*P/J Q0MB0db2 (cont.) => ('A2', 1, '01'),('A2', 2, '01'),('A2', 2 ,'02') \ITPUB个人空间.]+h p(Mx}\ D5s
db2 (cont.) => ), \
3B"N{4ShQCtG;@W0db2 (cont.) =>  t1(t11,t22,t33,t44,t55) as ( \
s aS w;E){"j0db2 (cont.) =>  select t1,t2,t3,rownumber() over(partition by t1,t2),rownumber() over(partition by t1,t2) as t4 from t \ITPUB个人空间fgL0CF*W
db2 (cont.) => ), \
2Y#N:Ex Om4S0db2 (cont.) => t3(s1,s2,s3,s4,s5) as( \
0GOvuT a8DW*ha0db2 (cont.) => select t11,t22,cast(t33 as varchar(100)),t44,t55 from t1 where T44 =1 and t55=1 \
{EyWE.{%i)i{^o}(Y0db2 (cont.) =>  union all \ITPUB个人空间"kY!TQ/X2bM
db2 (cont.) => select a.s1,a.s2,cast(a.s3||'-'||b.t33 as varchar(100)),a.s4+1,a.s5 from t3 a,t1 b \
guX.dA0t:I^t0db2 (cont.) =>  where a.s1=b.t11 and a.s4 = b.t55-1) \
n af;TW{2_$vr0db2 (cont.) => select s1,s2,s3 from t3 x where x.s4=(select max(s4) from t3 y where x.s1=y.s1) order by s1,s2ITPUB个人空间"@6H8A:a;^-q b

1Z"f+B a6XF7R0S1 S2          S3
"LN}4~T"j o/{0-- ----------- ----------------------------------------------------------------------------------------------------ITPUB个人空间DgT*wB5fi
SQL0347W  递归公共表表达式 "DB2ADMIN.T3" 可能包含无限循环。  SQLSTATE=01605ITPUB个人空间}f f/a sm"\P!^

0A5~"zA;On,H2_*V7v7F0A1           1 01-02-03
W_$W%v3@"g"@}0A2           1 01-02ITPUB个人空间5? _@'V&T"d J
A2           2 01-02ITPUB个人空间5U'L a,c7R ~ A E.@
ITPUB个人空间 n*Mx!m$h1Z2V
  已选择 3 条记录,打印 1 条警告消息。
&raH+CCW)I0ITPUB个人空间1rhv U/RZ[-iu

-UX5V/J!vr-Y0ok,搞定!ITPUB个人空间 qiXjd-f]6I/~.J

Z3Q?PZ T[0个人认为db2还是很强大的!大家一起学习ITPUB个人空间 AS nb\c

TAG:

我的家 引用 删除 lovelyman_gold   /   2008-08-16 09:38:39
good
good
wangzhonnew的个人空间 引用 删除 wangzhonnew   /   2008-07-30 19:48:39
5
 

评分:0

我来说两句

显示全部

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

日历

« 2008-10-08  
   1234
567891011
12131415161718
19202122232425
262728293031 

数据统计

  • 访问量: 10207
  • 日志数: 270
  • 图片数: 1
  • 文件数: 2
  • 建立时间: 2007-12-01
  • 更新时间: 2008-09-22

RSS订阅

Open Toolbar