a我考网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 151|回复: 1

[考试辅导] Oracle辅导:Oracle外键约束修改行为(七)

[复制链接]
发表于 2012-8-4 14:06:19 | 显示全部楼层 |阅读模式
Oracle的外键用来限制子表中参考的字段的值,必须在主表中存在。而且在主表的记录发生变化导致外键参考唯一约束值发生了变化时,定义了一系列的动作。; }- p. c  L8 U* f. I& Q# ]% r
  前面几篇文章介绍了Oracle所支持的3种约束行为NO ACTION、DELETE SET NULL和DELETE CASCADE.至于SQL标准中定义的其他操作,Oracle只能通过触发器来实现,这里给出一个简单的RESTRICT操作的例子。5 M1 ^3 w' R, N; T% c
  SQL> DROP TABLE T_C;
4 C3 `+ s) ~! M0 }- ?- D; j% \  表已删除。  \3 d$ J" g. B- P
  SQL> DROP TABLE T_P;
7 t, ?: i/ i" p. r  表已删除。3 E0 v& ^1 ^7 B- N+ x
  SQL> CREATE TABLE T_P (ID NUMBER, NAME VARCHAR2(30));" @) g9 s# S; `! R% D
  表已创建。
# J$ e$ E2 Q. ~2 Y8 Y  SQL> ALTER TABLE T_P ADD PRIMARY KEY (ID);( o  M8 C( R: ^6 o
  表已更改。1 y" \' d& {: |7 D8 q0 }$ K5 G
  SQL> CREATE TABLE T_C (ID NUMBER, FID NUMBER, NAME VARCHAR2(30));% x) X. b6 r- Q9 X- l( D
  表已创建。8 |# \9 E  ^9 B; G5 V
  SQL> ALTER TABLE T_C ADD CONSTRAINT FK_T_C
& Y" J7 \6 e5 t/ z/ N  2 FOREIGN KEY (FID)
" U4 y1 o! i4 e2 K  3 REFERENCES T_P (ID);/ n) |+ R; H8 H- ]2 t
  表已更改。
. L- w) S/ {$ c: H  SQL> INSERT INTO T_P VALUES (1, ’A’);
0 |  ]4 P0 V  B/ U6 o% S  已创建 1 行。
1 q: r5 l: W$ X- e0 e  SQL> INSERT INTO T_P VALUES (2, ’B’);
  J8 g9 Q: z' C# a  S7 v  已创建 1 行。
+ {) u0 k2 I0 C0 h$ H+ Z# U7 @  SQL> INSERT INTO T_C VALUES (1, 1, ’A’);# A; W. t$ Z( p& B& \8 @' |. o
  已创建 1 行。, B. v7 c' f& |6 t
  SQL> COMMIT;5 N% y4 |  R" I- b/ ^
  提交完成。
( Y+ \! r- q, D+ X  SQL标准定义的RESTRICT操作其实和NO ACTION操作十分类似。不同之处在于,RESTRICT的检查在语句执行之前,一旦发现主键被引用,就会报错,阻止更新或删除操作的执行。) I4 h7 B  f' B: y8 z4 t: x4 ^
  SQL> SELECT * FROM T_P;7 }$ Z6 M$ y  w5 k! d  X% f0 N9 K
  ID NAME! V  O5 {! b) S
  ---------- ------------------------------& q/ f8 L2 s& U' l. k0 j% y
  1 A4 d1 L/ ^9 r1 E5 Y
  2 B
9 M7 d6 p- E* `0 t; D7 w8 j  SQL> SELECT * FROM T_C;
4 N" x4 Z  l7 m# ]7 M  ID FID NAME  |2 u/ v' ]& T0 Q" C
  ---------- ---------- ------------------------------
; a' a9 U- U$ m  1 1 A
; s- M4 J5 k% e- T9 J  SQL> UPDATE T_P SET ID = 3 WHERE ID = 1;
% ^. i& A3 i. o1 @: B6 t  UPDATE T_P SET ID = 3 WHERE ID = 18 p& v6 D, O5 s, u5 [, d
  *第 1 行出现错误:
6 n) {- L8 m8 R( p" Q* |) w7 Y  ORA-02292: 违反完整约束条件 (YANGTK.FK_T_C) - 已找到子记录日志5 _8 F; |1 f+ _8 s: g
  对于上面这种情况,无论是NO ACTION还是RESTRICT,效果没有什么差别,而对于下面的情况就不一样了:2 A! Q! }8 q2 L. }$ V
  SQL> UPDATE T_P SET ID = ID - 1;" c( X# s! l0 F# z
  已更新2行。
) M, N+ B* G$ ~6 ?8 m% O& w( g5 ~  SQL> SELECT * FROM T_P;% }' e) y2 D, z1 U: A4 R- N. l/ r5 o
  ID NAME
) c7 [/ s. e% W3 e- W3 w  ---------- ------------------------------
  d! }3 j1 S8 F5 @0 i+ ]  0 A
0 l$ h$ ]4 v: h% G  1 B
2 u+ ]$ ^5 a5 Q# E. a  SQL> UPDATE T_P SET ID = ID + 1;: M. K6 U' y& ^! w. e
  已更新2行。7 n* U! ?' U* ^, f2 ?1 A
  SQL> SELECT * FROM T_P;
: z) b4 q/ \# O  ID NAME
% X1 f  J- {/ M: N  ---------- ------------------------------) a0 b) z; x5 g, {) u/ {* m
  1 A
3 [; ~' u: P) B3 f$ \* Z, ]  2 B
回复

使用道具 举报

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

Oracle辅导:Oracle外键约束修改行为(七)

  对于NO ACTION来说,约束的检查发生在语句之后,所有上面的语句可以顺利执行,而对于RESTRICT而言,这个操作会直接报错。& y4 w) L* t7 T, n
  下面构建一个RESTRICT操作的触发器:
+ l; x/ s' _$ A  M  SQL> CREATE OR REPLACE TRIGGER T_P_RESTRICT. l$ V$ W, H0 r7 t
  2 BEFORE DELETE OR UPDATE OF ID ON T_P
. L( M( [" ]5 T3 X/ f* D& r  3 FOR EACH ROW" \7 d7 Q: s# I. v6 g
  4 WHEN (NVL(NEW.ID, -1) != NVL(OLD.ID, -1))
& t; P7 g9 t2 Y* _  5 DECLARE  C* S1 ?/ b) y9 c( {
  6 V_STR VARCHAR2(32767);
# c% l3 L7 S5 J9 x  7 V_COUNT NUMBER;
6 ]8 N- _9 G' V" [4 ?  8 BEGIN
6 D, j8 w! C% k% f; c  9 FOR I IN (SELECT OWNER, TABLE_NAME, CONSTRAINT_NAME 6 I8 q: \, p; G! t/ I# ~7 g; S
  10 FROM ALL_CONSTRAINTS( w8 o; z( [/ S* X7 D
  11 WHERE CONSTRAINT_TYPE = ’R’
  k3 S- h7 h* u+ m: o- O  12 AND R_OWNER = ’YANGTK’9 O) P/ L8 b$ V# N) O
  13 AND R_CONSTRAINT_NAME IN
/ Y8 T: Z  `5 h' O5 u  14 (SELECT CONSTRAINT_NAME FROM USER_CONSTRAINTS WHERE TABLE_NAME = ’T_P’)): j% ]/ r( z, g; p9 _* N
  15 LOOP4 |' \8 a, w4 x8 p
  16 V_STR := ’SELECT COUNT(*) FROM ’ || I.TABLE_NAME || ’ WHERE ’;
+ r, ~$ Z. r; q- I0 R6 r  17 FOR J IN (SELECT COLUMN_NAME FROM ALL_CONS_COLUMNS
9 w2 |3 |, m& _% @  18 WHERE OWNER = I.OWNER
; a' i* q# t8 d2 N5 {1 C  19 AND TABLE_NAME = I.TABLE_NAME
& }5 ?# ]& ~$ U/ q1 q2 O8 ~7 @  20 AND CONSTRAINT_NAME = I.CONSTRAINT_NAME) 5 U4 w7 w' G1 r3 P9 {2 d  I
  21 LOOP
3 Z4 J  ^9 z4 j( Z/ b( ]  22 V_STR := V_STR || J.COLUMN_NAME || ’ = ’ || :OLD.ID;
6 n+ ^; ?% @0 G  23 END LOOP;
* R8 ^: \" X8 D  P( Q  24 EXECUTE IMMEDIATE V_STR INTO V_COUNT;3 b, m8 J+ Q. j5 ~* M  a. L
  25 IF V_COUNT > 0 THEN* g1 o5 r( H' C
  26 RAISE_APPLICATION_ERROR(-20001, ’违反完整约束条件限制操作 - 已找到子记录日志’);
. g& S% ]- G% a4 Z% T2 |  27 END IF;$ r2 U7 `3 f- B! l5 T
  28 END LOOP;1 C! n  `+ _# l( g! _+ Q7 g% M
  29 END;
2 ?. ]. l0 F4 s9 r& @  30 /
. t1 M9 @! Q/ X# r! {% b( t  触发器已创建
  H  J! L5 s0 d5 w! l/ ^" f( X  SQL> SELECT * FROM T_P;
) h7 t# B. P% }- U! @& z5 h. M: _  ID NAME2 y+ v# E8 y+ l* }! S! S
  ---------- ------------------------------6 R' c% _2 C! @, r
  1 A
/ C, s. z8 j/ q; C& G" U  2 B
+ `3 [! ~: N8 c8 A  SQL> SELECT * FROM T_C;
! X  [6 [8 O) v2 T! L2 r% E9 ^; Y  ID FID NAME" j  A! k4 |$ i0 _
  ---------- ---------- ------------------------------; @6 w% t+ Y( ^# H; ?
  1 1 A1 O3 P# [' P+ }: U# x# S; E% {
  SQL> UPDATE T_P SET ID = ID - 1;6 I$ A+ |  z' E, A) A' Z
  UPDATE T_P SET ID = ID - 1* B( }; j# O! V- W8 n% I2 A$ u- v
  *第 1 行出现错误:$ G* V" D* W! `0 t! c
  ORA-20001: 违反完整约束条件限制操作 - 已找到子记录日志
& X8 _3 Z( c- c3 V: W* w* f  ORA-06512: 在"YANGTK.T_P_RESTRICT", line 22
6 I# B2 o, Y, e  ORA-04088: 触发器 ’YANGTK.T_P_RESTRICT’ 执行过程中出错2 k. K2 X. [  w& j
  这种方式可以实现RESTRICT操作,但是对于其他会话的外键的引用,RESTRICT操作是看不到的:+ \# J# d+ ?7 U& w( `3 o7 B
  SQL> CONN YANGTK/YANGTK@YTK92已连接。
/ x. @; S: B' t5 u$ F4 R0 ^  SQL> SET SQLP ’SQL2> ’  q7 n7 `+ E( O$ q+ p
  SQL2> INSERT INTO T_C VALUES (2, 2, ’B’);
9 {, f; l- r2 J9 l$ @6 n  已创建 1 行。. p; f7 Q3 P9 [7 G5 ^1 e1 j5 I
  在另一个会话插入一条参考主表ID为2的记录,且不提交,这时在主表更新或删除ID为2的记录时,会被锁住,RESTRICT操作不会起作用,因为这时看不到其他用户未提交的修改:
4 a4 _* a+ B: b8 D' M  SQL> DELETE T_P WHERE ID = 2;+ y6 Y4 c3 _$ g' `: S8 N
  而如果在第二个会话中提交事务:
: \; d% I6 T# e6 T  SQL2> COMMIT;
& s% L$ ?5 W6 s& V  l1 K  提交完成。- {& ]6 J4 s  ?* G
  则RESTRICT操作会起作用,因为这时已经提交,而当前的会话是可以看到其他会话中已提交数据的:* h0 ^( A# I* X) E( }8 x/ b
  DELETE T_P WHERE ID = 2' b$ \1 S; ?# j* M+ l( C8 H
  *第 1 行出现错误:* ?/ h) _" C5 p/ M1 J) t* v
  ORA-20001: 违反完整约束条件限制操作 - 已找到子记录日志3 W& P" d, b$ |: u9 I2 B- E
  ORA-06512: 在"YANGTK.T_P_RESTRICT", line 22
& s1 l8 @3 [$ \3 d8 r0 t, J  ORA-04088: 触发器 ’YANGTK.T_P_RESTRICT’ 执行过程中出错' e2 A4 ~$ D% a( c: F# T) h
  SQL>
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-5-5 21:58 , Processed in 0.217091 second(s), 23 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

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