a我考网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 166|回复: 1

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

[复制链接]
发表于 2012-8-4 14:06:19 | 显示全部楼层 |阅读模式
Oracle的外键用来限制子表中参考的字段的值,必须在主表中存在。而且在主表的记录发生变化导致外键参考唯一约束值发生了变化时,定义了一系列的动作。7 {, m! s0 r9 u) V% N( C
  前面几篇文章介绍了Oracle所支持的3种约束行为NO ACTION、DELETE SET NULL和DELETE CASCADE.至于SQL标准中定义的其他操作,Oracle只能通过触发器来实现,这里给出一个简单的RESTRICT操作的例子。
# x; \; F# X! G- H( l, g  SQL> DROP TABLE T_C;& |# H; l# F  Z, |" P# b, h2 x
  表已删除。
# C' n* y$ {5 W4 R2 t  SQL> DROP TABLE T_P;) n; c/ [& A" M' F! u( H
  表已删除。' f- h, t1 n! P8 T
  SQL> CREATE TABLE T_P (ID NUMBER, NAME VARCHAR2(30));% T; r; v/ M/ b5 u/ V6 W$ k5 N7 c
  表已创建。
1 Q) ]4 l6 @9 @4 D5 e' E, Y  SQL> ALTER TABLE T_P ADD PRIMARY KEY (ID);
; R5 |' w% l2 I9 J  表已更改。& P% t3 O& Q! }5 R$ B4 L
  SQL> CREATE TABLE T_C (ID NUMBER, FID NUMBER, NAME VARCHAR2(30));6 r7 a8 h' x7 W8 d
  表已创建。
, V9 P0 w8 g8 a2 C! ^; l  SQL> ALTER TABLE T_C ADD CONSTRAINT FK_T_C
) C. [, n7 b6 M; Y' m7 X! ?3 s  2 FOREIGN KEY (FID)$ f, n% K- S  X5 Z
  3 REFERENCES T_P (ID);
2 w5 @# Z( v- m6 D( y. Y1 h0 e  表已更改。. R  b8 e7 B( z# [0 B8 \  t
  SQL> INSERT INTO T_P VALUES (1, ’A’);
( H1 m# P) j2 w* _; X$ R* v  已创建 1 行。
. a! |0 L1 ~4 J# v- S' P  SQL> INSERT INTO T_P VALUES (2, ’B’);
, d  Z8 l9 `3 \+ S$ i  已创建 1 行。( U2 g( x/ K+ A, D
  SQL> INSERT INTO T_C VALUES (1, 1, ’A’);$ p6 H1 Q$ y3 N* ?" Q$ j7 D( ?
  已创建 1 行。
2 u6 N; C* p- p$ p) k  SQL> COMMIT;
4 p' E2 c) F% A# e7 ^* J! c  提交完成。/ z# m; I& {$ u& L( b4 S6 L
  SQL标准定义的RESTRICT操作其实和NO ACTION操作十分类似。不同之处在于,RESTRICT的检查在语句执行之前,一旦发现主键被引用,就会报错,阻止更新或删除操作的执行。! r9 @) Y) U& M$ H, g
  SQL> SELECT * FROM T_P;
' z5 `* b6 K" Q% I* B  ID NAME# r  M) o  I) Z" v3 q! y7 U
  ---------- ------------------------------) }' u/ q6 r( ?& h% Z2 R# ~* h% N
  1 A
5 S0 h9 ~, Q. p( \  j: ^' q  2 B
' s9 ?9 N) C4 U8 T  V$ i. B6 Q  SQL> SELECT * FROM T_C;
/ R3 A5 D) D% z6 n8 p3 C4 z  ID FID NAME$ C5 D) S( _, n
  ---------- ---------- ------------------------------
; f2 ]! ^" e- G9 u( ^2 M  1 1 A
+ m: {; o( ^4 i3 E: W- c9 _  SQL> UPDATE T_P SET ID = 3 WHERE ID = 1;1 s; a/ @$ r2 d5 q
  UPDATE T_P SET ID = 3 WHERE ID = 1
. @; a9 Z, ?6 j, T  *第 1 行出现错误:' z8 L4 N6 c: C0 c1 A( t
  ORA-02292: 违反完整约束条件 (YANGTK.FK_T_C) - 已找到子记录日志
& K& Y( D, o* ?% K# z  对于上面这种情况,无论是NO ACTION还是RESTRICT,效果没有什么差别,而对于下面的情况就不一样了:( p5 a* E- Y( |, X
  SQL> UPDATE T_P SET ID = ID - 1;! n3 X( I: A# k# n) Z+ L
  已更新2行。8 `, ^  e/ l% g' W. [
  SQL> SELECT * FROM T_P;
6 L; n# }# S) y% c. y  ID NAME
7 [: v$ j1 c5 ?1 ]4 i  ---------- ------------------------------! _8 U7 o- J' m% L* H- m7 i
  0 A
. {0 Y$ \1 I( L6 ^- B4 X  1 B& x) p7 I4 p5 p/ X, {2 B8 `3 @
  SQL> UPDATE T_P SET ID = ID + 1;
' [4 T! g% c* R' u; H  已更新2行。) u; J& q' r) Y# U, p
  SQL> SELECT * FROM T_P;
8 C5 W5 @# k1 {% D( ~+ O  ID NAME
2 C6 ]/ k* {  E* r  ---------- ------------------------------+ G) o3 S) I) B9 g% S" z: \! @% K
  1 A  E$ W5 Q" Z" w" R- m
  2 B
回复

使用道具 举报

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

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

  对于NO ACTION来说,约束的检查发生在语句之后,所有上面的语句可以顺利执行,而对于RESTRICT而言,这个操作会直接报错。
; V8 @" `8 i+ u1 L0 ]5 L/ N% _7 q/ f  下面构建一个RESTRICT操作的触发器:* x+ X1 [4 a6 J. y+ K+ v% c! I1 a
  SQL> CREATE OR REPLACE TRIGGER T_P_RESTRICT! ]7 _3 w( F5 Y4 m1 @
  2 BEFORE DELETE OR UPDATE OF ID ON T_P' ]1 X& Y4 P( C" @6 L) s
  3 FOR EACH ROW( A; G+ k- t: y+ |8 \  Z  b
  4 WHEN (NVL(NEW.ID, -1) != NVL(OLD.ID, -1))
5 F. }1 N/ O# F. F  N/ Q  5 DECLARE
/ N9 q* s: V  q& `  6 V_STR VARCHAR2(32767);& b2 O4 w3 c9 h" B
  7 V_COUNT NUMBER;
6 w' f% G$ X& I$ x; {7 A" V  8 BEGIN
/ o7 T8 v) L0 ?( L  Y, B  9 FOR I IN (SELECT OWNER, TABLE_NAME, CONSTRAINT_NAME 4 J. f" P2 [/ Z. D$ J( F2 N  p4 X
  10 FROM ALL_CONSTRAINTS
: |$ M8 i& C# T# p- ^' L. a  11 WHERE CONSTRAINT_TYPE = ’R’6 J3 j$ u! y/ f/ a! X( j
  12 AND R_OWNER = ’YANGTK’
+ B1 j  f0 K- C, d/ k2 ^  13 AND R_CONSTRAINT_NAME IN
  R- [  z: C, Q  14 (SELECT CONSTRAINT_NAME FROM USER_CONSTRAINTS WHERE TABLE_NAME = ’T_P’))8 B; K. E- q' k% S) Q
  15 LOOP
  W4 u( m* H3 {7 U  K  16 V_STR := ’SELECT COUNT(*) FROM ’ || I.TABLE_NAME || ’ WHERE ’; 2 Z, _# B0 J, Y8 {2 u
  17 FOR J IN (SELECT COLUMN_NAME FROM ALL_CONS_COLUMNS 7 Y& p8 y0 p" ~# V
  18 WHERE OWNER = I.OWNER4 w) J9 X7 u6 y5 M0 T" i# M
  19 AND TABLE_NAME = I.TABLE_NAME
5 K+ f6 B9 E) q2 t5 [/ Y+ o  20 AND CONSTRAINT_NAME = I.CONSTRAINT_NAME) ! E. Q( L+ B2 |& L
  21 LOOP
* T- q+ p) ]" E8 N% D, `  22 V_STR := V_STR || J.COLUMN_NAME || ’ = ’ || :OLD.ID;
( _2 G9 P4 d7 Y9 G% `  23 END LOOP;
6 ~, g2 l* ~5 K7 D" t- m! J  c& t  24 EXECUTE IMMEDIATE V_STR INTO V_COUNT;
% U+ l& k* ]! I/ y5 P" x( }3 r  25 IF V_COUNT > 0 THEN
; ^( l0 x6 L2 @2 I  V2 ]1 u  26 RAISE_APPLICATION_ERROR(-20001, ’违反完整约束条件限制操作 - 已找到子记录日志’);& q0 x# g0 t: u4 G& T
  27 END IF;
+ @# ^; M3 R( _6 F+ P$ @/ h* [9 E  28 END LOOP;
$ p6 @! b, X) Z& ?' D6 v; E  29 END;5 ~# v$ Y; f; ^5 F9 Q; M! Q4 s
  30 /+ C* ~+ U% {0 E4 h6 R2 O+ @( f) W
  触发器已创建  M$ Z8 j% M# @! W' w
  SQL> SELECT * FROM T_P;# `5 o+ W$ e* f4 W7 t* ^# g% u/ u
  ID NAME& D* t# Z% A% ?, c+ a: s
  ---------- ------------------------------
6 @8 t/ y6 x" G% X( y9 t- B  1 A
$ G1 {1 f8 t( ^: D+ k  2 B5 R. c. W3 Q" l6 H! c7 b
  SQL> SELECT * FROM T_C;0 E5 |% }- m  P( L/ Q
  ID FID NAME
9 J4 G) {0 U* }+ y  ---------- ---------- ------------------------------
+ h, |# V3 |+ R) S- c  1 1 A! V1 F1 ~3 ~+ Y
  SQL> UPDATE T_P SET ID = ID - 1;8 e8 V0 t1 W1 L& n# _
  UPDATE T_P SET ID = ID - 1
9 \3 @, s1 c3 n. X+ i0 }  *第 1 行出现错误:  Y( G: ~4 u& q( J" T
  ORA-20001: 违反完整约束条件限制操作 - 已找到子记录日志
# f/ Q+ a( J, Q9 h9 F* q* z; M  ORA-06512: 在"YANGTK.T_P_RESTRICT", line 223 F7 X, P. }5 p0 w/ [$ f
  ORA-04088: 触发器 ’YANGTK.T_P_RESTRICT’ 执行过程中出错8 C9 f) h+ Y$ o" Y
  这种方式可以实现RESTRICT操作,但是对于其他会话的外键的引用,RESTRICT操作是看不到的:
; E$ ^5 @6 h+ I: v% Z  SQL> CONN YANGTK/YANGTK@YTK92已连接。
* `! |8 a' t& s  SQL> SET SQLP ’SQL2> ’
$ t: ]2 D+ D$ ]( a- y, j& I8 i  SQL2> INSERT INTO T_C VALUES (2, 2, ’B’);
0 O6 V' w% N( e  已创建 1 行。
" e% x/ K/ Z3 q5 a2 |- C* T  在另一个会话插入一条参考主表ID为2的记录,且不提交,这时在主表更新或删除ID为2的记录时,会被锁住,RESTRICT操作不会起作用,因为这时看不到其他用户未提交的修改:
" {2 ~1 D8 k8 Z  SQL> DELETE T_P WHERE ID = 2;  W9 Y) B5 |# B) Z' n. f
  而如果在第二个会话中提交事务:
( V- l) |1 O- @+ q) w" R* C  SQL2> COMMIT;2 B# ^8 H) W" H8 a
  提交完成。; ]0 I4 B! ^3 X$ U; P2 m8 _3 I$ i/ m
  则RESTRICT操作会起作用,因为这时已经提交,而当前的会话是可以看到其他会话中已提交数据的:  Z" I. M/ M/ c4 U+ V% J
  DELETE T_P WHERE ID = 2
$ a' _' ~3 I) s6 \# `  G# N1 m  *第 1 行出现错误:' A2 I" q6 y" F6 u; A; s# ^7 h9 U
  ORA-20001: 违反完整约束条件限制操作 - 已找到子记录日志
4 e4 `5 y: c, y8 T  ORA-06512: 在"YANGTK.T_P_RESTRICT", line 22
; ^/ Q: Z) S8 A+ s  ORA-04088: 触发器 ’YANGTK.T_P_RESTRICT’ 执行过程中出错
9 M0 K' \2 G) u& R/ y- V  SQL>
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-9-28 08:14 , Processed in 0.205841 second(s), 24 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

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