a我考网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 143|回复: 2

[综合] Oracle辅导:ORACLE多表关联的update语句

[复制链接]
发表于 2012-8-4 13:54:49 | 显示全部楼层 |阅读模式
 为了便利起见,成立了以下简单模子,和机关了部门测试数据:   在某个营业受理子系统BSS中,
4 \4 y0 @$ L7 a8 P: c& h  --客户资料表
4 \" ~) a2 b( H  create table customers
9 Z6 H6 |$ @+ ?: a  (
7 u! B6 b3 [  {( \' f, U& I  customer_id   number(8)    not null,  -- 客户标示
5 l, r9 E1 E: b8 v( y' G% t( v% E  city_name     varchar2(10) not null,  -- 地址城市* M8 B4 a! P  I) E8 n+ c* N
  customer_type char(2)      not null,  -- 客户类型
% c6 c3 E2 l3 @$ o  ...7 B/ }% p4 J, Z& x  C
  )6 _( V0 Y% x5 q$ O; k- y
  create unique index PK_customers on customers (customer_id)! [1 q$ i2 q4 N0 p
  因为某些原因,客户地址城市这个信息并不什么切确,可是在3 L. A8 z; T8 ~) _
  客户处事部的CRM子系统中,经由过程自动处事获取了部食客户20%的地址/ ~. h( _9 B! p& K2 l2 o. q$ A
  城市等切确信息,于是你将该部门信息提取至一张姑且表中:
9 u& ~% l* A1 Q; w  create table tmp_cust_city
$ w! i1 [- ^+ ~$ U$ n: h( `+ a6 t  (
1 _, z( d# ^9 U  customer_id    number(8) not null,
2 ^4 q4 v/ V3 S8 i  citye_name     varchar2(10) not null,4 U; Y) b2 w3 U3 K; C6 p' b/ y! J' n
  customer_type  char(2)   not null
* p* c5 g3 ]) i# r3 I" r; X3 z) i1 X  )- H- l7 f3 M7 ^2 v% L+ A* |' b
  1) 最简单的形式
# _& v' P$ D9 q. E+ m0 R! e( h  --经确认customers表中所有customer_id小于1000均为'北京'
' y( [; T; m  ^  --1000以内的均是公司走向全国之前的本城市的老客户:)/ c( x+ n' A% B1 D* t
  update customers/ x2 E$ W( ?% }; v* H( P. e* h
  set    city_name='北京': X0 \: u+ W( O" a3 |# `& [
) k2 s& O% ]' X( _7 ?; t3 u
  where  customer_id
回复

使用道具 举报

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

Oracle辅导:ORACLE多表关联的update语句

</p>  2) 两表(多表)联系关系update -- 仅在where字句中的毗连: x5 `* F9 f. m2 L# E* \# X/ k
  --此次提取的数据都是VIP,且搜罗新增的,所以顺便更新客户类别
) q3 o6 b. F1 `  update customers  a       -- 使用别号+ k, B" `5 A- `. \. m! |
  set    customer_type='01' --01 为vip,00为通俗
  D/ {: h2 b# a  where  exists (select 1, S% h# N$ }/ N
  from   tmp_cust_city b
9 ], l" {( g; f$ s' ]# N. x  where  b.customer_id=a.customer_id# z& Y3 ?0 H  B+ p! ?% E
  )- z/ ^5 h: v, A8 x  E  I
  3) 两表(多表)联系关系update -- 被改削值由另一个表运算而来- o+ h6 J1 H' E% i
  update customers a   -- 使用别号5 Q* t0 u1 t$ y7 {
  set    city_name=(select b.city_name from tmp_cust_city b where b.customer_id=a.customer_id)3 a9 q% w+ @2 G' X
  where  exists (select 1
/ H0 e  q# D2 _0 Z, s4 A% a1 w* [' D  from   tmp_cust_city b- j* J, d5 S; @/ @5 i' D2 j( q
  where  b.customer_id=a.customer_id
# \/ j& U, J" S/ t3 U8 I  )
6 N* h4 z9 q+ ]' Z: E/ D; N  -- update 跨越2个值' [8 c; g: M4 d/ X5 r1 I- _* ^) ]" i
  update customers a   -- 使用别号+ b2 y9 ]: a* X' _9 c' v6 [9 x0 Q* E
  set    (city_name,customer_type)=(select b.city_name,b.customer_type
/ {% q% A9 C; g7 [  from   tmp_cust_city b* |' ^) q4 m4 t2 u* v$ F
  where  b.customer_id=a.customer_id)
5 @6 r% P6 E: |/ F) E# j  where  exists (select 1/ l% f5 |! d* i6 O* V6 W  V
  from   tmp_cust_city b7 O8 [! H! j1 x) b  t
  where  b.customer_id=a.customer_id
9 X8 z! s8 P6 V  )" K0 M5 p# o  }! R( c
  注重在这个语句中,2 Q7 }5 s4 w8 b1 e  m0 q
  =(select b.city_name,b.customer_type
/ k/ h* n2 L9 `" B  from   tmp_cust_city b
, W8 p! I4 l7 j0 W; x  where  b.customer_id=a.customer_id4 c8 Q1 ]7 p' Y9 |
  )
- }2 H  Z! G% r# F8 [) V  与
4 a2 |! ~) E+ |) l) j! f  (select 1
; k9 G; T% w/ N1 F- E1 d. o  from   tmp_cust_city b. I- z+ j. F0 _! N3 X+ Y' J
  where  b.customer_id=a.customer_id5 E9 B- J. q4 Z" B5 e
  )
0 U& e3 c# j' Q+ u+ v  F( x  是两个自力的子发芽,查看执行打算可知,对b表/索引扫描了2篇;# P* x1 S7 L+ \) e: Q
  如不美观舍弃where前提,则默认对A表进行全表
0 o: F- B5 n# b  更新,但因为(select b.city_name from tmp_cust_city b where
: H5 v0 C1 G; z" E  where  b.customer_id=a.customer_id)4 {2 R/ Q4 h' S& ]7 K
  有可能不能供给"足够多"值,因为tmp_cust_city只是一部食客户的信息,$ }: o1 p+ n. H
  所以报错(如不美观指定的列--city_name可觉得NULL则另当别论):# Z0 O7 t' @7 \5 |7 w% s# R, ^, I
  01407, 00000, "cannot update (%s) to NULL"' H4 z2 f/ J$ j! C
  // *Cause:
$ u8 u2 p5 n$ Z: L  // *Action:
9 p" O# J: e: D+ \. b% z  一个替代的体例可以采用:  Y) U) m! X: q$ O1 F+ y
  update customers a   -- 使用别号
* ^2 b' s6 `4 }$ Y  set    city_name=nvl((select b.city_name from tmp_cust_city b; [* L8 A2 {; Z* @* ^
  where b.customer_id=a.customer_id),a.city_name)5 V0 L' T" f; u2 n7 J4 i( ~
  或者
/ Z6 ]" o% f, Y- N! c6 d  set    city_name=nvl((select b.city_name from tmp_cust_city b
, K' |) [* z+ f  where b.customer_id=a.customer_id),'未知')
7 X% |# a/ b9 o, H2 j. J  ^! |/ `. P: A/ G+ a
  -- 当然这不合适营业逻辑了
回复 支持 反对

使用道具 举报

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

Oracle辅导:ORACLE多表关联的update语句

</p>  4) 上述3)在一些情形下,因为B表的记载只有A表的20-30%的记载数,5 ~! g+ B& G" H" a/ B8 Y
  考虑A表使用INDEX的情形,使用cursor也许会比联系关系update带来更好的机能:9 w6 y8 ?, ?& l  \1 ^* ^
  set serveroutput on* O: y; v: k9 D! y$ D
  declare
; l( q7 s& N  A% f! |. i  cursor city_cur is0 W, ?. G3 h0 ?4 \( j
  select customer_id,city_name
7 D8 v' M2 ]2 x) E- C, x  from   tmp_cust_city- H; [$ K+ W. {8 m4 y, ^: W' p
  order by customer_id;
8 G$ l, H; q' h: ~/ |  begin- S: Q) a! S- b2 M# o6 I5 B- @
  for my_cur in city_cur loop7 `9 G0 X5 N2 U% |2 k
  update customers
/ b  ^0 m/ r9 T  {  E4 x2 ?  set    city_name=my_cur.city_name
% k" o+ C" v; D7 a  where  customer_id=my_cur.customer_id;
1 i" e, m0 L# z9 Z7 U, b* Q) V  /** 此处也可以单条/分批次提交,避免锁表情形 **/8 k: ~2 H' w) h. Z2 y3 p" o$ w# |
  --     if mod(city_cur%rowcount,10000)=0 then
( f: |- V! q8 m  --        dbms_output.put_line('----');
% }6 p, \9 M2 g  --        commit;
$ s! |3 P! E0 _) L% G: u& {/ ?  --     end if;* g. I1 r+ K6 ]8 d8 y6 x; q( b6 S2 e
  end loop;4 M# [$ J5 O1 g( r1 y
  end;
: a( y' t2 r, g& [  5) 联系关系update的一个特例以及机能再切磋) V; |% r# B  C% s5 b2 S7 X
  在oracle的update语句语法中,除了可以update表之外,也可所以视图,所以有以下1个特例:
4 y, ?/ r2 L. n- \' }  update (select a.city_name,b.city_name as new_name
8 T4 j; T% n( S: K2 c( [  from   customers a,! ~  V) Y; Z4 T, A' p9 F
  tmp_cust_city b' K6 [3 i# e2 d
  where  b.customer_id=a.customer_id, D9 A9 {1 |- {2 Z5 r( ?
  )
' {2 y% e9 {) h$ L' m  set    city_name=new_name
, S. Q5 R* Q6 \. U  这样能避免对B表或其索引的2次扫描,但前提是 A(customer_id) b(customer_id)必需是unique index
" _5 P  t: c; F6 j  或primary key。否则报错:% v0 k+ f1 M% x4 W) {! E: ]) A
  01779, 00000, "cannot modify a column which maps to a non key-preserved table"0 i2 r3 e* K+ b* n7 M/ V$ M7 k8 P
  // *Cause: An attempt was made to insert or update columns of a join view which
8 Z( O# ^- q' r  //         map to a non-key-preserved table.. g- o+ n( q: w  z
  // *Action: Modify the underlying base tables directly.; |" b/ ~9 ?. h( q
  6)oracle另一个常见错误. K1 H4 O5 |  d- c7 H
  回到3)情形,因为某些原因,tmp_cust_city customer_id 不是独一index/primary key
) U7 G8 B/ N# I/ A+ U/ T  update customers a   -- 使用别号
2 S4 C# b7 N6 Q: R/ P  set    city_name=(select b.city_name from tmp_cust_city b where b.customer_id=a.customer_id)
" Z  ^! q( u' N  F$ ~  where  exists (select 1
9 |/ n% d1 L+ D9 i' `5 q7 r4 s3 n  from   tmp_cust_city b
. |- @5 ?$ I9 r$ a) _  where  b.customer_id=a.customer_id% C4 _6 [5 W5 y
  )$ }, P  \1 t* V! B
  当对于一个给定的a.customer_id
5 z* \: `0 H5 K3 ]% i6 _! f' g  (select b.city_name from tmp_cust_city b where b.customer_id=a.customer_id)
/ v, ]- C$ m0 x9 C: z: U1 I* E  返回多余1条的情形,则会报如下错误:$ g1 f1 E+ e& W. l/ h
  01427, 00000, "single-row subquery returns more than one row"0 }2 }' y+ M! p& w* ~6 {
  // *Cause:
5 y* a( n, C6 F6 x& S) N2 z  // *Action:
6 h) }; I: ?$ Y; ?1 N. |2 l5 u2 o  一个斗劲简单近似于不负责任的做法是  h& K% K+ r, b! u( `1 |. E
  update customers a   -- 使用别号2 C( y8 P) y( V1 h& p- F( U- |
  set    city_name=(select b.city_name from tmp_cust_city b where b.customer_id=a.customer_id)& p+ z; S- s& v# ~. \
  若何理解 01427 错误,在一个很复杂的多表毗连update的语句,经常因考虑不周,呈现这个错误,
4 J; T9 Z* ?- A  仍已上述例子来描述,一个斗劲精练的体例就是将A表代入 值表达式 中,使用group by 和
  w- T" h7 ^) x: w  having 字句查垂青复的记载
' F9 I3 G4 d" P& S; g1 p  (select b.customer_id,b.city_name,count(*)& x9 u* r4 }- k8 F
  from tmp_cust_city b,customers a/ F  U, f% w7 O' i- a4 w
  where b.customer_id=a.customer_id
3 q/ A- B. G+ l1 U, \4 l( H2 q  group by b.customer_id,b.city_name; T) N9 G( a6 [; Y* l* p: F
  having count(*)>=2
6 S( v6 H8 D- H5 k  ]/ Z  )
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-5-22 15:39 , Processed in 0.187456 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

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