a我考网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 260|回复: 3

[考试辅导] 怎样删除Oracle数据库中的冗余数据(二)

[复制链接]
发表于 2012-8-4 14:06:19 | 显示全部楼层 |阅读模式
 它将冗余数据选择到一个游标中,并根据(LastName,FirstName)来分组(在我们这个方案中),然后打开游标然后循环地取出每一行,然后用与先前的取出的键值进行比较,如果这是第一次取出这个值,或者这个值不是冗余键,那么跳过这个记录然后取下一个,不然的话,这就是这个组中的冗余记录,所以删掉它.   让我们运行一下这个存储过程
) o% Z1 a& k% |, g$ S/ r. J% i( W+ M/ L# v4 R  BEGIN7 K; K- p) o: a# m; ]' c
  DeleteDuplicates;
" \& v, `; r  _# l5 M) n  R7 u2 g  END;4 r( Q1 w) `7 A3 t! p
  /
/ R; @$ v# y$ R" G) s# m  SELECT LastName, FirstName, COUNT(*)
$ w/ v- U7 Y2 C5 |$ m  FROM Customers
+ I" x" f: s$ k( r$ G% o" h* n  GROUP BY LastName, FirstName$ I$ y; ~- A6 B7 W9 c+ S% G* Q$ q
  HAVING COUNT(*) > 1;" n& s/ s4 [1 m5 S, b. H" v4 O) e
  最后一个查询语句没有返回值,所以冗余数据没有了从表中取冗余数据的过程完全是由定义在csr_Duplicates 这个游标中的SQL语句来实现的,PL/SQl只是用来实现删除冗余数,那么能不能完全用SQL语句来实现呢?
3 @7 {3 n3 g: S& R( d7 M  p1 y+ d  二.SQL解决方案,使用RANK()删除冗余数据Oracle8i分析函数RANK()来枚举每一个组中的元素,在我们的方案中, 我们应用这个方案,我们使用这个函数动态的把冗余数据连续的排列起来加上编号,组由Partintion by 这个语句来分开,然后用Order by 进行分组 SELECT ID, LastName, FirstName, RANK() OVER (PARTITION BY LastName,& V0 a- Y. i& ?$ x
  FirstName ORDER BY ID) SeqNumber
. ~% E  C# V! T( ^, ~  FROM Customers% \6 ?" w9 Q# i
  ORDER BY LastName, FirstName;
4 F0 N, L+ S4 k7 D  SQL  }. ]9 i: g1 v3 _. C* e
  Listing 7. Output of single SQL statement that uses RANK()
! @+ \$ r9 q: o7 f; c* x  显示的是根据记录的条数的个数来显示尤其对于冗余数据
7 F7 y/ @/ P( d, o. [) F3 x  ID LASTNAME FIRSTNAME SEQNUMBER
/ N) I; {, G0 ?. z9 c2 I+ D) y: d1 l- M
  ----- --------------- ---------- ----------
回复

使用道具 举报

 楼主| 发表于 2012-8-4 14:06:20 | 显示全部楼层

怎样删除Oracle数据库中的冗余数据(二)

</p>  1018 Blake Becky 1
, H0 N! x+ o" u7 z$ B) V& [  1013 Blue Don 1  B  V9 _, A- O3 [0 P; s6 }3 K
  1000 Bradley Tom 11 q% `0 V3 M) P0 o' W
  1002 Chang Jim 10 P( M9 I4 M; F  c1 B
  1008 Griffith David 1- ]3 G/ q1 W' \8 _" t/ V( g
  1020 Hill Larry 14 c, M2 t0 V4 t- A- J! c7 j# f8 P# _
  1004 King Chuck 1
9 m+ `0 h  h% T% h3 H& |- h& K+ q  1005 Krieger Jeff 1# B( s  m3 `6 ^
  1012 Krieger Jeff 2
+ {% _/ }- e& s  1017 Krieger Jeff 3# D. A: X. [4 a- P- @
  1003 Loney Julie 1
$ W: n* t) ]3 {# \7 N) N  1007 Lord Don 1
2 t: M6 ^$ ~9 E! m' }" O; m* P  1015 Mason Paul 1. N% R1 z4 t( v! ^
  1006 Monroe John 1
, E" o7 h. \8 i: ^' g$ D  1009 Simon Michael 1) c- k) ~% S: e* l
  1010 Simon Michael 2+ J1 d% }! H  q! k! d# l
  1001 Stone Tony 1# M; t6 q% C8 u7 e* O
  1011 Stone Tony 2+ \5 [; u8 E* C, g+ |8 t4 @
  1014 Stone Tony 3
5 }5 U3 R0 ~9 Y. F& p5 w1 N/ N( u% h  1016 Stone Tony 4# x/ _1 Y+ C1 c* L
  1019 Stone Tony 5
6 q3 D+ K% N( q  我们可以看一到,SeqNumber这一列中的数值,冗余数据是根据ID号由小到大进行的排序,所有的冗余数据的SqlNumber都大于一,所有的非冗余数据都等于一,所以我们取自己所需,删除那么没用的SELECT ID, LastName, FirstName
5 `' S5 k0 s, k9 S# @  FROM
- _+ P( x9 T+ Z9 }  (SELECT ID, LastName, FirstName, RANK() OVER (PARTITION BY LastName,  ?1 W' a& E& O- p% J
  FirstName ORDER BY ID) AS SeqNumber9 |0 }, ]1 Y3 \. D$ w
  FROM Customers)
7 [. P" {& E+ C3 X  WHERE SeqNumber > 1;, h& r5 s. A1 f6 \& |$ N$ @5 e
  SQL4 F8 G9 A+ Y' v# ?7 Q8 g3 m
  Listing 8. 冗余键的键值
  V; A! E. I) b8 _+ ], P  有七行必须被删除
8 k2 O' H  |4 |+ d( _0 a1 b, c; b  ID LASTNAME FIRSTNAME
7 i! y1 y+ t: V8 D) u  ----- --------------- ----------
% z! Z) T' b/ }( O1 N  1012 Krieger Jeff& J. l" P; L: ]0 o% {/ h
  1017 Krieger Jeff4 ~+ E( e1 f; K% P
  1010 Simon Michael
8 {/ n8 {+ }2 C& p( i3 I  1011 Stone Tony
) Y4 p/ t+ n6 ~; T4 r9 ?4 t' Y  1014 Stone Tony7 Q' {! F2 b4 e7 e& m5 |2 @. E
  1016 Stone Tony
" d: f5 z) n4 \& F; r: B
6 I/ \3 a& H5 Z" B2 z4 f# G6 Z' y, d. ^  1019 Stone Tony
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-8-4 14:06:21 | 显示全部楼层

怎样删除Oracle数据库中的冗余数据(二)

</p>  7 rows selected.这显示有七行需要删除,还是用上一个表我测试了一下这个代码,它用了77秒种就删除了所有的数据准备好了用Sql语句来删除冗余数据,版本一它执行了135秒: f9 ^6 _; S1 K! u5 f# e) J, ]: b( W
  DELETE
. u8 x# g- v2 [/ B  FROM CUSTOMERS
- V2 I4 n! [0 c  S6 X  WHERE ID IN
: w6 B! N0 I: {/ D0 y; x  (SELECT ID- C6 [% K: ?% \* [( D; g' m+ ]
  FROM5 u; q0 @  t+ P5 s4 s! n6 C/ c
  (SELECT ID, LastName, FirstName, RANK() OVER (PARTITION BY LastName,
9 O: D* d+ w1 ?' _9 m  FirstName ORDER BY ID) AS SeqNumber3 m5 C" x5 i5 S( F
  FROM Customers)
6 N/ j2 P! v% T( G  WHERE SeqNumber > 1);
: Q1 ~6 W3 m1 D" p$ K  我们可以看到最后的两行语句对表中的数据进行了排序,这不是有效的,所以我们来优化一下最后一个查询语句,把Rank()函数应用到只含有冗余数据的组,而不是所有的列下面这个语句是比较有效率的,虽然它不像上一个查询那样精简SELECT ID, LastName, FirstName3 y8 D6 I0 ^) k) _, ^& h
  FROM4 w! p- q9 s$ @9 b: F& g. k
  (SELECT ID, LastName, FirstName, RANK() OVER (PARTITION BY LastName,# |0 u' W  k; N' F* Y: n. X3 j
  FirstName ORDER BY ID) AS SeqNumber
1 ]! j/ C% ]9 e; g; |  FROM! v# |( R, i. ~% J* p) e% [" I
  (SELECT ID, LastName, FirstName# Q4 C5 q4 M- N5 y# {6 Q+ J
  FROM Customers
, t, _. p. b$ m  WHERE (LastName, FirstName) IN (SELECT LastName, FirstName! z/ Y$ ^5 r+ ]
  FROM Customers4 R( \5 ]  u( u1 U3 A
  GROUP BY LastName, FirstName5 f6 |. K5 s% s" e( D/ E
  HAVING COUNT(*) > 1)))
5 d1 b$ G8 {6 \: G- ~  WHERE SeqNumber > 1;
8 x% A- K& H* f5 z$ B& U' f  选择冗余数据只用了26秒钟,这样就提高了67%的性能,这样就提高了将这个作为子查询的删除查询的效率,
. M7 {8 ~/ ?7 `  r' y! d1 P  DELETE8 L: u: W: |* \+ f+ c
  FROM Customers" c* s& G6 n1 \- x
  WHERE ID IN
. \0 T) C5 O) S: x* D* m9 F  (SELECT ID
# Z& f  x! ~! H+ n  FROM9 r8 a$ C& n2 t0 c2 O8 b
  (SELECT ID, LastName, FirstName, RANK() OVER (PARTITION BY LastName,
. Y. O$ S8 h  X, d5 F8 p2 u  FirstName ORDER BY ID) AS SeqNumber
4 f* ]; A0 l7 u6 P0 C  FROM
# N9 E. D2 P/ F/ }( s/ M  (SELECT ID, LastName, FirstName
  N" R7 ^! H0 \! p$ J% _6 C! t  FROM Customers3 {* g0 r& b0 g1 y: `
  WHERE (LastName, FirstName) IN (SELECT LastName, FirstName
& j5 C' g6 O+ c( Z4 d' `- G& U8 Z& q  FROM Customers7 w- G6 b7 S5 |- b9 {( s$ D
  GROUP BY LastName, FirstName
5 O. Z4 o9 I# k$ G8 w6 Z0 b% d  HAVING COUNT(*) > 1)))
: j: N; w$ V' p8 S# ~) l$ g6 A# P4 I
  WHERE SeqNumber > 1);
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-8-4 14:06:22 | 显示全部楼层

怎样删除Oracle数据库中的冗余数据(二)

</p>  现在只用了47秒钟的就完成的上面的任务,比起上一个136秒,这是一个很大的进步,相比之下,存储过程用了56秒,这样存储过程有些慢了使用PL/SQL语句我们和我们以上的代码,会得到更好的更精确的代码,和提高你代码的执行效率,虽然对于从数据库中枚举数据PL/SQL对于Sql两者没有什么差别,但是对于数据的比较上,PL/SQL就比SQL要快很多,但是如果冗余数据量比较小的话,我们尽量使用SQL而不使用PL/SQL如果你的数据表没有主键的话,那么你可以参考其它技术
) D; H5 @  R+ P' K2 {: `  Rank()其它的方法. M. [) P6 }# V8 E# q
  使用Rank()函数你可以对选择你所保留的数据,(或者是小ID的或者是大ID 的,就由RECDate这个列来决定这种情况下,你可以把REcdate加入到(Orderby )子句中,倒序或者正序
/ ]9 o/ |* _! c6 F  这是一种保留最大Id的一种解决方案
0 C% Z6 l  O1 ^/ Z) p  Z  DELETE
4 P  f* U( N! s/ G9 x  FROM Customers: @+ U+ ]6 ^! D) _& N1 {: m
  WHERE ID IN  J; S2 B& B0 ^3 c
  (SELECT ID, c. T! X8 R& b1 C2 w8 B
  FROM
$ G3 z1 C7 v$ H' u: {0 D  (SELECT ID, LastName, FirstName, RANK() OVER (PARTITION BY LastName, FirstName ORDER BY RecDate DESC, ID) AS SeqNumber# [" c2 u5 I" A) F- a$ X  l
  FROM  J% {4 B9 w, Q- Z9 _$ M% Y
  (SELECT ID, LastName, FirstName, RecDate
: u2 }+ F/ P1 x$ {) q2 s) ^  FROM Customers
- M! e1 _* [7 h$ f* q0 I, ^4 L  WHERE (LastName, FirstName) IN (SELECT LastName, FirstName* `. C3 ?7 q6 F: V) P; x' K. w) H
  FROM Customers
" G' n: h) J( T  ^0 u2 _( Z  GROUP BY LastName, FirstName3 [/ t  i9 M% X( u4 Y4 I
  HAVING COUNT(*) > 1)))% R$ d5 n; v( t3 f' [- d
  WHERE SeqNumber > 1);5 u/ I+ W+ T1 V1 a
  这种技术保证了你可以控制每一个表中的保留的组,假设你有一个数据库,有一个促销或者有一个折扣信息,比如一个团体可以使用这种促销5次,或者个人可以使用这个折扣三次,为了指出要保留的组的个数,你可以在where 和having子句中进行设置,那么你将删除所有大于你
* N. `3 A# Y# c' |2 r3 J  设置有数的冗余组0 M7 i- g: U) Z0 c: _. N
  DELETE
2 X, m: E- [- Y! b# ^  FROM Customers4 W- W2 I8 u7 ?* o  P4 L
  WHERE ID IN& x, o  W, V& g: g; C. O
  (SELECT ID
6 z' z# C/ q2 w& ~& }  FROM
- d0 H4 B) ~& W5 F. t' {5 @+ r  (SELECT ID, LastName, FirstName, RANK() OVER (PARTITION BY LastName,
& D; y+ Y1 u3 j5 e  ?( y' Y# r  FirstName ORDER BY ID) AS SeqNumber6 l( e9 T' `% v  N4 {
  FROM/ _3 m7 r2 W! G& ]; c: H0 _5 s. P
  (SELECT ID, LastName, FirstName
/ P) b' f5 b6 m0 C  FROM Customers
0 w" g# E) |8 ?- P  WHERE (LastName, FirstName) IN (SELECT LastName, FirstName
& f  P" w% Q- a  FROM Customers6 u) z0 b* H) S( U% s7 P
  GROUP BY LastName, FirstName& Z7 Q- m5 k2 d- S9 J+ N
  HAVING COUNT(*) > 3)))
9 L5 X1 u# l- S" @  WHERE SeqNumber > 3);
7 w4 C9 u0 h0 K& \  @4 E3 S! M2 D+ S  As you can see, using the RANK() function allows you to eliminate duplicates in a
$ ]; F$ _2 G5 U2 d  single SQL statement and gives you more capabilities by extending the power of3 y* c; I2 Y: q; I
  your
. M# C4 k. F& ~6 f1 B) [# B  queries.
) b3 F5 t$ _6 w% e* h  正如你所见使用Rank()可以消除冗余数据而且能给你很大的可伸展性
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-5-6 03:56 , Processed in 0.172889 second(s), 27 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

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