日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

小议Oracle外键约束修改行为

發(fā)布時間:2024/8/26 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 小议Oracle外键约束修改行为 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
小議Oracle外鍵約束修改行為(一)
Oracle的外鍵用來限制子表中參考的字段的值,必須在主表中存在。而且在主表的記錄發(fā)生變化導(dǎo)致外鍵參考唯一約束值發(fā)生了變化時,定義了一系列的動作。






在SQL92標(biāo)準(zhǔn)中定義了幾種外鍵改變后,如何處理子表記錄的動作,其中包括:


限制Restrict:這種方式不允許對被參考的記錄的鍵值執(zhí)行更新或刪除的操作;


置為空Set to null:當(dāng)參考的數(shù)據(jù)被更新或者刪除,那么所有參考它的外鍵值被置為空;


置為默認(rèn)值Set to default:當(dāng)參考的數(shù)據(jù)被更新或者刪除,那么所有參考它的外鍵值被置為一個默認(rèn)值;


級聯(lián)Cascade:當(dāng)參考的數(shù)據(jù)被更新,則參考它的值同樣被更新,當(dāng)參考的數(shù)據(jù)被刪除,則參考它的子表記錄也被刪除;


不做操作No action:這種方式不允許更新或刪除被參考的數(shù)據(jù)。和限制方式的區(qū)別在于,這種方式的檢查發(fā)生在語句執(zhí)行之后。Oracle默認(rèn)才會的方式就是這種方式。


Oracle明確支持的方式包括No action、Set to null和Cascade。對于Set to Default和Restrict,Oracle的約束類型并不直接支持,不過可以通過觸發(fā)器來實現(xiàn)。


簡單看一下Oracle的默認(rèn)處理方式No action:


SQL> CREATE TABLE T_P (ID NUMBER, NAME VARCHAR2(30));


表已創(chuàng)建。


SQL> ALTER TABLE T_P ADD PRIMARY KEY (ID);


表已更改。


SQL> CREATE TABLE T_C (ID NUMBER, FID NUMBER, NAME VARCHAR2(30));


表已創(chuàng)建。


SQL> ALTER TABLE T_C ADD CONSTRAINT FK_T_C
2 FOREIGN KEY (FID)
3 REFERENCES T_P (ID);


表已更改。


SQL> INSERT INTO T_P VALUES (1, 'A');


已創(chuàng)建 1 行。


SQL> INSERT INTO T_P VALUES (2, 'B');


已創(chuàng)建 1 行。


SQL> INSERT INTO T_C VALUES (1, 1, 'A');


已創(chuàng)建 1 行。


SQL> COMMIT;


提交完成。


對于No Action操作而言,如果主鍵的記錄被外鍵所參考,那么主鍵記錄是無法更新或刪除的。


SQL> DELETE T_P WHERE ID = 1;
DELETE T_P WHERE ID = 1
*第 1 行出現(xiàn)錯誤:
ORA-02292: 違反完整約束條件 (YANGTK.FK_T_C) - 已找到子記錄日志




SQL> UPDATE T_P SET ID = 3 WHERE ID = 1;
UPDATE T_P SET ID = 3 WHERE ID = 1
*第 1 行出現(xiàn)錯誤:
ORA-02292: 違反完整約束條件 (YANGTK.FK_T_C) - 已找到子記錄日志




SQL> DELETE T_P WHERE ID = 2;


已刪除 1 行。


不過No Action又和Restrict操作有所區(qū)別,No Action允許用戶執(zhí)行語句,在語句執(zhí)行之后,或者事務(wù)結(jié)束的時候才會檢查是否違反約束。而Restrict只有檢測到有外鍵參考主表的記錄,就不允許刪除和更新的操作執(zhí)行了。


這也使得No Action操作支持延遲約束:


SQL> ALTER TABLE T_C DROP CONSTRAINT FK_T_C;


表已更改。


SQL> ALTER TABLE T_C ADD CONSTRAINT FK_T_C
2 FOREIGN KEY (FID)
3 REFERENCES T_P (ID)
4 DEFERRABLE INITIALLY DEFERRED;


表已更改。


SQL> SELECT * FROM T_P;


ID NAME
---------- ------------------------------
1 A


SQL> SELECT * FROM T_C;


ID FID NAME
---------- ---------- ------------------------------
1 1 A


SQL> DELETE T_P WHERE ID = 1;


已刪除 1 行。


SQL> INSERT INTO T_P VALUES (1, 'A');


已創(chuàng)建 1 行。


SQL> COMMIT;


提交完成。


小議Oracle外鍵約束修改行為(二)
Oracle的外鍵用來限制子表中參考的字段的值,必須在主表中存在。而且在主表的記錄發(fā)生變化導(dǎo)致外鍵參考唯一約束值發(fā)生了變化時,定義了一系列的動作。


這篇簡單描述一下SET TO NULL操作。


小議Oracle外鍵約束修改行為(一):http://yangtingkun.itpub.net/post/468/478045






上一篇描述了Oracle外鍵處理默認(rèn)操作:No Action,這里簡單介紹一下SET TO NULL操作。還是利用前面例子的表,不過約束需要重建。


SQL> DROP TABLE T_C;


表已刪除。


SQL> DROP TABLE T_P;


表已刪除。


SQL> CREATE TABLE T_P (ID NUMBER, NAME VARCHAR2(30));


表已創(chuàng)建。


SQL> ALTER TABLE T_P ADD PRIMARY KEY (ID);


表已更改。


SQL> CREATE TABLE T_C (ID NUMBER, FID NUMBER, NAME VARCHAR2(30));


表已創(chuàng)建。


SQL> ALTER TABLE T_C ADD CONSTRAINT FK_T_C
2 FOREIGN KEY (FID)
3 REFERENCES T_P (ID)
4 ON DELETE SET NULL;


表已更改。


SQL> INSERT INTO T_P VALUES (1, 'A');


已創(chuàng)建 1 行。


SQL> INSERT INTO T_P VALUES (2, 'B');


已創(chuàng)建 1 行。


SQL> INSERT INTO T_C VALUES (1, 1, 'A');


已創(chuàng)建 1 行。


SQL> INSERT INTO T_C VALUES (2, 2, 'B');


已創(chuàng)建 1 行。


SQL> INSERT INTO T_C VALUES (3, 1, 'C');


已創(chuàng)建 1 行。


SQL> COMMIT;


提交完成。


下面檢查一下DELETE SET NULL是如何工作的:


SQL> SELECT * FROM T_P;


ID NAME
---------- ------------------------------
1 A
2 B


SQL> SELECT * FROM T_C;


ID FID NAME
---------- ---------- ------------------------------
1 1 A
2 2 B
3 1 C


SQL> DELETE T_P WHERE ID = 2;


已刪除 1 行。


SQL> SELECT * FROM T_C;


ID FID NAME
---------- ---------- ------------------------------
1 1 A
2 B
3 1 C


SQL> UPDATE T_P SET ID = 3;
UPDATE T_P SET ID = 3
*第 1 行出現(xiàn)錯誤:
ORA-02292: 違反完整約束條件 (YANGTK.FK_T_C) - 已找到子記錄日志


可以看到這個Set no null的操作和語法中的名稱一樣,只對DELETE操作有效,而對于UPDATE操作無效。


這個約束操作還有一個前提,就是要求子表的外鍵列允許為空,否則對主表的DELETE操作會報錯:


SQL> SELECT * FROM T_C;


ID FID NAME
---------- ---------- ------------------------------
1 1 A
2 B
3 1 C


SQL> DELETE T_C WHERE ID = 2;


已刪除 1 行。


SQL> ALTER TABLE T_C MODIFY FID NOT NULL;


表已更改。


SQL> DELETE T_P;
DELETE T_P
*第 1 行出現(xiàn)錯誤:
ORA-01407: 無法更新 ("YANGTK"."T_C"."FID") 為 NULL


從這里也可以看到,雖然Oracle支持Set to null,但是只是實現(xiàn)了DELETE語句,而沒有實現(xiàn)UPDATE語句,這和SQL標(biāo)準(zhǔn)的定義還是有區(qū)別的。


小議Oracle外鍵約束修改行為(三)
Oracle的外鍵用來限制子表中參考的字段的值,必須在主表中存在。而且在主表的記錄發(fā)生變化導(dǎo)致外鍵參考唯一約束值發(fā)生了變化時,定義了一系列的動作。


這篇簡單描述一下CASCADE操作。


小議Oracle外鍵約束修改行為(一):http://yangtingkun.itpub.net/post/468/478045


小議Oracle外鍵約束修改行為(二):http://yangtingkun.itpub.net/post/468/478119






上一篇描述了Oracle外鍵處理操作:SET TO NULL,這里簡單介紹一下CASCADE操作。還是利用前面例子的表,不過約束需要重建。


SQL> DROP TABLE T_C;


表已刪除。


SQL> DROP TABLE T_P;


表已刪除。


SQL> CREATE TABLE T_P (ID NUMBER, NAME VARCHAR2(30));


表已創(chuàng)建。


SQL> ALTER TABLE T_P ADD PRIMARY KEY (ID);


表已更改。


SQL> CREATE TABLE T_C (ID NUMBER, FID NUMBER, NAME VARCHAR2(30));


表已創(chuàng)建。


SQL> ALTER TABLE T_C ADD CONSTRAINT FK_T_C
2 FOREIGN KEY (FID)
3 REFERENCES T_P (ID)
4 ON DELETE CASCADE;


表已更改。


SQL> INSERT INTO T_P VALUES (1, 'A');


已創(chuàng)建 1 行。


SQL> INSERT INTO T_P VALUES (2, 'B');


已創(chuàng)建 1 行。


SQL> INSERT INTO T_C VALUES (1, 1, 'A');


已創(chuàng)建 1 行。


SQL> INSERT INTO T_C VALUES (2, 2, 'B');


已創(chuàng)建 1 行。


SQL> INSERT INTO T_C VALUES (3, 1, 'C');


已創(chuàng)建 1 行。


SQL> COMMIT;


提交完成。


下面看看CASCADE是如何工作的:


SQL> SELECT * FROM T_P;


ID NAME
---------- ------------------------------
1 A
2 B


SQL> SELECT * FROM T_C;


ID FID NAME
---------- ---------- ------------------------------
1 1 A
2 2 B
3 1 C


SQL> DELETE T_P WHERE ID = 2;


已刪除 1 行。


SQL> SELECT * FROM T_C;


ID FID NAME
---------- ---------- ------------------------------
1 1 A
3 1 C


SQL> UPDATE T_P SET ID = 3 WHERE ID = 1;
UPDATE T_P SET ID = 3 WHERE ID = 1
*第 1 行出現(xiàn)錯誤:
ORA-02292: 違反完整約束條件 (YANGTK.FK_T_C) - 已找到子記錄日志


可以看到,和SET TO NULL約束一樣,CASCADE操作也是只對DELETE語句有效,而對于UPDATE語句不起作用。


另外提一句,和SET TO NULL不同,CASCADE具有傳遞性,主表刪除一條記錄,會導(dǎo)致子表參考的記錄被刪除,而子表的記錄被刪除又會導(dǎo)致子表的子表記錄被刪除:


SQL> ALTER TABLE T_C ADD PRIMARY KEY (ID);


表已更改。


SQL> CREATE TABLE T_C_C (ID NUMBER PRIMARY KEY, FID NUMBER,?
2 CONSTRAINT FK_T_C_C FOREIGN KEY (FID) REFERENCES T_C(ID) ON DELETE CASCADE);


表已創(chuàng)建。


SQL> INSERT INTO T_C_C VALUES (1, 1);


已創(chuàng)建 1 行。


SQL> CREATE TABLE T_C_C_C (ID NUMBER PRIMARY KEY, FID NUMBER,?
2 CONSTRAINT FK_T_C_C_C FOREIGN KEY (FID) REFERENCES T_C_C(ID) ON DELETE CASCADE);


表已創(chuàng)建。


SQL> INSERT INTO T_C_C_C VALUES (1, 1);


已創(chuàng)建 1 行。


SQL> COMMIT;


提交完成。


下面看看級聯(lián)刪除的效果:


SQL> SELECT * FROM T_P;


ID NAME
---------- ------------------------------
1 A


SQL> SELECT * FROM T_C;


ID FID NAME
---------- ---------- ------------------------------
1 1 A
3 1 C


SQL> SELECT * FROM T_C_C;


ID FID
---------- ----------
1 1


SQL> SELECT * FROM T_C_C_C;


ID FID
---------- ----------
1 1


SQL> DELETE T_P;


已刪除 1 行。


SQL> SELECT * FROM T_P;


未選定行


SQL> SELECT * FROM T_C;


未選定行


SQL> SELECT * FROM T_C_C;


未選定行


SQL> SELECT * FROM T_C_C_C;


未選定行


小議Oracle外鍵約束修改行為(四)
Oracle的外鍵用來限制子表中參考的字段的值,必須在主表中存在。而且在主表的記錄發(fā)生變化導(dǎo)致外鍵參考唯一約束值發(fā)生了變化時,定義了一系列的動作。


這篇描述一下如何實現(xiàn)UPDATE CASCADE。


小議Oracle外鍵約束修改行為(一):http://yangtingkun.itpub.net/post/468/478045


小議Oracle外鍵約束修改行為(二):http://yangtingkun.itpub.net/post/468/478119


小議Oracle外鍵約束修改行為(三):http://yangtingkun.itpub.net/post/468/478172






前面幾篇文章介紹了Oracle所支持的3種約束行為NO ACTION、DELETE SET NULL和DELETE CASCADE。


至于SQL標(biāo)準(zhǔn)中定義的其他操作,Oracle只能通過觸發(fā)器來實現(xiàn),這里給出一個簡單的UPDATE CASCADE操作的例子。


SQL> DROP TABLE T_C;


表已刪除。


SQL> DROP TABLE T_P;


表已刪除。


SQL> CREATE TABLE T_P (ID NUMBER, NAME VARCHAR2(30));


表已創(chuàng)建。


SQL> ALTER TABLE T_P ADD PRIMARY KEY (ID);


表已更改。


SQL> CREATE TABLE T_C (ID NUMBER, FID NUMBER, NAME VARCHAR2(30));


表已創(chuàng)建。


SQL> ALTER TABLE T_C ADD CONSTRAINT FK_T_C
2 FOREIGN KEY (FID)
3 REFERENCES T_P (ID);


表已更改。


SQL> INSERT INTO T_P VALUES (1, 'A');


已創(chuàng)建 1 行。


SQL> INSERT INTO T_P VALUES (2, 'B');


已創(chuàng)建 1 行。


SQL> INSERT INTO T_C VALUES (1, 1, 'A');


已創(chuàng)建 1 行。


SQL> COMMIT;


提交完成。


檢查一下直接更新操作:


SQL> SELECT * FROM T_P;


ID NAME
---------- ------------------------------
1 A
2 B


SQL> SELECT * FROM T_C;


ID FID NAME
---------- ---------- ------------------------------
1 1 A


SQL> UPDATE T_P SET ID = 3 WHERE ID = 1;
UPDATE T_P SET ID = 3 WHERE ID = 1
*第 1 行出現(xiàn)錯誤:
ORA-02292: 違反完整約束條件 (YANGTK.FK_T_C) - 已找到子記錄日志


下面構(gòu)造一個觸發(fā)器:


SQL> CREATE OR REPLACE TRIGGER T_P_UPDATE_CASCADE?
2 BEFORE UPDATE OF ID ON T_P?
3 FOR EACH ROW
4 WHEN (NVL(NEW.ID, -1) != NVL(OLD.ID, -1))
5 DECLARE
6 V_STR VARCHAR2(32767);
7 BEGIN
8 FOR I IN (SELECT OWNER, TABLE_NAME, CONSTRAINT_NAME?
9 FROM ALL_CONSTRAINTS
10 WHERE CONSTRAINT_TYPE = 'R'
11 AND R_OWNER = 'YANGTK'
12 AND R_CONSTRAINT_NAME IN?
13 (SELECT CONSTRAINT_NAME FROM USER_CONSTRAINTS WHERE TABLE_NAME = 'T_P'))
14 LOOP
15 V_STR := 'UPDATE ' || I.TABLE_NAME || ' SET ';?
16 FOR J IN (SELECT COLUMN_NAME FROM ALL_CONS_COLUMNS?
17 WHERE OWNER = I.OWNER
18 AND TABLE_NAME = I.TABLE_NAME?
19 AND CONSTRAINT_NAME = I.CONSTRAINT_NAME)?
20 LOOP
21 V_STR := V_STR || J.COLUMN_NAME || ' = ' || :NEW.ID?
22 || ' WHERE ' || J.COLUMN_NAME || ' = ' || :OLD.ID;
23 END LOOP;
24 EXECUTE IMMEDIATE V_STR;
25 END LOOP;
26 END;
27 /


觸發(fā)器已創(chuàng)建


SQL> SELECT * FROM T_P;


ID NAME
---------- ------------------------------
1 A
2 B


SQL> SELECT * FROM T_C;


ID FID NAME
---------- ---------- ------------------------------
1 1 A


SQL> UPDATE T_P SET ID = 3 WHERE ID = 1;


已更新 1 行。


SQL> SELECT * FROM T_P;


ID NAME
---------- ------------------------------
3 A
2 B


SQL> SELECT * FROM T_C;


ID FID NAME
---------- ---------- ------------------------------
1 3 A


采用動態(tài)SQL的好處是,即使新增了新的外鍵表,觸發(fā)器也不用重新編輯:


SQL> CREATE TABLE T_C1 (ID NUMBER, FID NUMBER, CONSTRAINT FK_T_C1?
2 FOREIGN KEY (FID) REFERENCES T_P);


表已創(chuàng)建。


SQL> INSERT INTO T_C1 VALUES (1, 3);


已創(chuàng)建 1 行。


SQL> UPDATE T_P SET ID = 1 WHERE ID = 3;


已更新 1 行。


SQL> SELECT * FROM T_P;


ID NAME
---------- ------------------------------
1 A
2 B


SQL> SELECT * FROM T_C;


ID FID NAME
---------- ---------- ------------------------------
1 1 A


SQL> SELECT * FROM T_C1;


ID FID
---------- ----------
1 1


小議Oracle外鍵約束修改行為(五)
Oracle的外鍵用來限制子表中參考的字段的值,必須在主表中存在。而且在主表的記錄發(fā)生變化導(dǎo)致外鍵參考唯一約束值發(fā)生了變化時,定義了一系列的動作。


這篇描述一下如何實現(xiàn)UPDATE SET NULL。


小議Oracle外鍵約束修改行為(一):http://yangtingkun.itpub.net/post/468/478045


小議Oracle外鍵約束修改行為(二):http://yangtingkun.itpub.net/post/468/478119


小議Oracle外鍵約束修改行為(三):http://yangtingkun.itpub.net/post/468/478172


小議Oracle外鍵約束修改行為(四):http://yangtingkun.itpub.net/post/468/478280






前面幾篇文章介紹了Oracle所支持的3種約束行為NO ACTION、DELETE SET NULL和DELETE CASCADE。


至于SQL標(biāo)準(zhǔn)中定義的其他操作,Oracle只能通過觸發(fā)器來實現(xiàn),這里給出一個簡單的UPDATE SET NULL操作的例子。


SQL> DROP TABLE T_C;


表已刪除。


SQL> DROP TABLE T_P;


表已刪除。


SQL> CREATE TABLE T_P (ID NUMBER, NAME VARCHAR2(30));


表已創(chuàng)建。


SQL> ALTER TABLE T_P ADD PRIMARY KEY (ID);


表已更改。


SQL> CREATE TABLE T_C (ID NUMBER, FID NUMBER, NAME VARCHAR2(30));


表已創(chuàng)建。


SQL> ALTER TABLE T_C ADD CONSTRAINT FK_T_C
2 FOREIGN KEY (FID)
3 REFERENCES T_P (ID);


表已更改。


SQL> INSERT INTO T_P VALUES (1, 'A');


已創(chuàng)建 1 行。


SQL> INSERT INTO T_P VALUES (2, 'B');


已創(chuàng)建 1 行。


SQL> INSERT INTO T_C VALUES (1, 1, 'A');


已創(chuàng)建 1 行。


SQL> COMMIT;


提交完成。


檢查一下直接更新操作:


SQL> SELECT * FROM T_P;


ID NAME
---------- ------------------------------
1 A
2 B


SQL> SELECT * FROM T_C;


ID FID NAME
---------- ---------- ------------------------------
1 1 A


SQL> UPDATE T_P SET ID = 3 WHERE ID = 1;
UPDATE T_P SET ID = 3 WHERE ID = 1
*第 1 行出現(xiàn)錯誤:
ORA-02292: 違反完整約束條件 (YANGTK.FK_T_C) - 已找到子記錄日志


下面構(gòu)造一個觸發(fā)器:


SQL> CREATE OR REPLACE TRIGGER T_P_SET_NULL?
2 BEFORE UPDATE OF ID ON T_P?
3 FOR EACH ROW
4 WHEN (NVL(NEW.ID, -1) != NVL(OLD.ID, -1))
5 DECLARE
6 V_STR VARCHAR2(32767);
7 BEGIN
8 FOR I IN (SELECT OWNER, TABLE_NAME, CONSTRAINT_NAME?
9 FROM ALL_CONSTRAINTS
10 WHERE CONSTRAINT_TYPE = 'R'
11 AND R_OWNER = 'YANGTK'
12 AND R_CONSTRAINT_NAME IN?
13 (SELECT CONSTRAINT_NAME FROM USER_CONSTRAINTS WHERE TABLE_NAME = 'T_P'))
14 LOOP
15 V_STR := 'UPDATE ' || I.TABLE_NAME || ' SET ';?
16 FOR J IN (SELECT COLUMN_NAME FROM ALL_CONS_COLUMNS?
17 WHERE OWNER = I.OWNER
18 AND TABLE_NAME = I.TABLE_NAME?
19 AND CONSTRAINT_NAME = I.CONSTRAINT_NAME)?
20 LOOP
21 V_STR := V_STR || J.COLUMN_NAME || ' = NULL '
22 || 'WHERE ' || J.COLUMN_NAME || ' = ' || :OLD.ID;
23 END LOOP;
24 EXECUTE IMMEDIATE V_STR;
25 END LOOP;
26 END;
27 /


觸發(fā)器已創(chuàng)建


SQL> SELECT * FROM T_P;


ID NAME
---------- ------------------------------
1 A
2 B


SQL> SELECT * FROM T_C;


ID FID NAME
---------- ---------- ------------------------------
1 1 A


SQL> UPDATE T_P SET ID = 3 WHERE ID = 1;


已更新 1 行。


SQL> SELECT * FROM T_P;


ID NAME
---------- ------------------------------
3 A
2 B


SQL> SELECT * FROM T_C;


ID FID NAME
---------- ---------- ------------------------------
1 A


UPDATE SET NULL操作其實和UPDATE CASCADE很相似,不同之處無非是一個置為NULL,另一個置為主鍵的新值。


小議Oracle外鍵約束修改行為(六)
Oracle的外鍵用來限制子表中參考的字段的值,必須在主表中存在。而且在主表的記錄發(fā)生變化導(dǎo)致外鍵參考唯一約束值發(fā)生了變化時,定義了一系列的動作。


這篇描述一下如何實現(xiàn)SET DEFAULT。


小議Oracle外鍵約束修改行為(一):http://yangtingkun.itpub.net/post/468/478045


小議Oracle外鍵約束修改行為(二):http://yangtingkun.itpub.net/post/468/478119


小議Oracle外鍵約束修改行為(三):http://yangtingkun.itpub.net/post/468/478172


小議Oracle外鍵約束修改行為(四):http://yangtingkun.itpub.net/post/468/478280


小議Oracle外鍵約束修改行為(五):http://yangtingkun.itpub.net/post/468/478374






前面幾篇文章介紹了Oracle所支持的3種約束行為NO ACTION、DELETE SET NULL和DELETE CASCADE。


至于SQL標(biāo)準(zhǔn)中定義的其他操作,Oracle只能通過觸發(fā)器來實現(xiàn),這里給出一個簡單的SET DEFAULT操作的例子。


SQL> DROP TABLE T_C;


表已刪除。


SQL> DROP TABLE T_P;


表已刪除。


SQL> CREATE TABLE T_P (ID NUMBER, NAME VARCHAR2(30));


表已創(chuàng)建。


SQL> ALTER TABLE T_P ADD PRIMARY KEY (ID);


表已更改。


SQL> CREATE TABLE T_C (ID NUMBER, FID NUMBER, NAME VARCHAR2(30));


表已創(chuàng)建。


SQL> ALTER TABLE T_C ADD CONSTRAINT FK_T_C
2 FOREIGN KEY (FID)
3 REFERENCES T_P (ID);


表已更改。


SQL> INSERT INTO T_P VALUES (1, 'A');


已創(chuàng)建 1 行。


SQL> INSERT INTO T_P VALUES (2, 'B');


已創(chuàng)建 1 行。


SQL> INSERT INTO T_C VALUES (1, 1, 'A');


已創(chuàng)建 1 行。


SQL> COMMIT;


提交完成。


檢查一下直接更新操作:


SQL> SELECT * FROM T_P;


ID NAME
---------- ------------------------------
1 A
2 B


SQL> SELECT * FROM T_C;


ID FID NAME
---------- ---------- ------------------------------
1 1 A


SQL> UPDATE T_P SET ID = 3 WHERE ID = 1;
UPDATE T_P SET ID = 3 WHERE ID = 1
*第 1 行出現(xiàn)錯誤:
ORA-02292: 違反完整約束條件 (YANGTK.FK_T_C) - 已找到子記錄日志


下面構(gòu)造一個觸發(fā)器:


SQL> CREATE OR REPLACE TRIGGER T_P_SET_DEFAULT?
2 BEFORE DELETE OR UPDATE OF ID ON T_P
3 FOR EACH ROW
4 WHEN (NVL(NEW.ID, -1) != NVL(OLD.ID, -1))
5 DECLARE
6 V_STR VARCHAR2(32767);
7 BEGIN
8 FOR I IN (SELECT OWNER, TABLE_NAME, CONSTRAINT_NAME?
9 FROM ALL_CONSTRAINTS
10 WHERE CONSTRAINT_TYPE = 'R'
11 AND R_OWNER = 'YANGTK'
12 AND R_CONSTRAINT_NAME IN?
13 (SELECT CONSTRAINT_NAME FROM USER_CONSTRAINTS WHERE TABLE_NAME = 'T_P'))
14 LOOP
15 V_STR := 'UPDATE ' || I.TABLE_NAME || ' SET ';?
16 FOR J IN (SELECT A.COLUMN_NAME, B.DATA_DEFAULT
17 FROM ALL_CONS_COLUMNS A, ALL_TAB_COLUMNS B
18 WHERE A.OWNER = I.OWNER
19 AND B.OWNER = I.OWNER
20 AND A.TABLE_NAME = I.TABLE_NAME
21 AND B.TABLE_NAME = I.TABLE_NAME?
22 AND A.COLUMN_NAME = B.COLUMN_NAME
23 AND CONSTRAINT_NAME = I.CONSTRAINT_NAME)?
24 LOOP
25 V_STR := V_STR || J.COLUMN_NAME || ' = ' || J.DATA_DEFAULT?
26 || ' WHERE ' || J.COLUMN_NAME || ' = ' || :OLD.ID;
27 END LOOP;
28 EXECUTE IMMEDIATE V_STR;
29 END LOOP;
30 END;
31 /


觸發(fā)器已創(chuàng)建


SQL> ALTER TABLE T_C MODIFY FID DEFAULT 2;


表已更改。


SQL> SELECT * FROM T_P;


ID NAME
---------- ------------------------------
1 A
2 B


SQL> SELECT * FROM T_C;


ID FID NAME
---------- ---------- ------------------------------
1 1 A


SQL> UPDATE T_P SET ID = 3 WHERE ID = 1;


已更新 1 行。


SQL> SELECT * FROM T_P;


ID NAME
---------- ------------------------------
3 A
2 B


SQL> SELECT * FROM T_C;


ID FID NAME
---------- ---------- ------------------------------
1 2 A


下面檢查一下DELETE操作是否有效:


SQL> UPDATE T_C SET FID = 3;


已更新 1 行。


SQL> SELECT * FROM T_C;


ID FID NAME
---------- ---------- -----------------------------
1 3 A


SQL> DELETE T_P WHERE ID = 3;


已刪除 1 行。


SQL> SELECT * FROM T_P;


ID NAME
---------- ------------------------------
2 B


SQL> SELECT * FROM T_C;


ID FID NAME
---------- ---------- -----------------------------
1 2 A


小議Oracle外鍵約束修改行為(七)


上一篇 / 下一篇 ?2009-02-13 22:05:02 / 個人分類:ORACLE
查看( 131 ) / 評論( 0 ) / 評分( 0 / 0 )
Oracle的外鍵用來限制子表中參考的字段的值,必須在主表中存在。而且在主表的記錄發(fā)生變化導(dǎo)致外鍵參考唯一約束值發(fā)生了變化時,定義了一系列的動作。
這篇描述一下如何實現(xiàn)RESTRICT。
小議Oracle外鍵約束修改行為(一):http://yangtingkun.itpub.net/post/468/478045
小議Oracle外鍵約束修改行為(二):http://yangtingkun.itpub.net/post/468/478119
小議Oracle外鍵約束修改行為(三):http://yangtingkun.itpub.net/post/468/478172
小議Oracle外鍵約束修改行為(四):http://yangtingkun.itpub.net/post/468/478280
小議Oracle外鍵約束修改行為(五):http://yangtingkun.itpub.net/post/468/478374
小議Oracle外鍵約束修改行為(六):http://yangtingkun.itpub.net/post/468/478437
?
?
前面幾篇文章介紹了Oracle所支持的3種約束行為NO ACTION、DELETE SET NULL和DELETE CASCADE。
至于SQL標(biāo)準(zhǔn)中定義的其他操作,Oracle只能通過觸發(fā)器來實現(xiàn),這里給出一個簡單的RESTRICT操作的例子。
SQL> DROP TABLE T_C;


表已刪除。


SQL> DROP TABLE T_P;


表已刪除。


SQL> CREATE TABLE T_P (ID NUMBER, NAME VARCHAR2(30));


表已創(chuàng)建。


SQL> ALTER TABLE T_P ADD PRIMARY KEY (ID);


表已更改。


SQL> CREATE TABLE T_C (ID NUMBER, FID NUMBER, NAME VARCHAR2(30));


表已創(chuàng)建。


SQL> ALTER TABLE T_C ADD CONSTRAINT FK_T_C
??2 ?FOREIGN KEY (FID)
??3 ?REFERENCES T_P (ID);


表已更改。


SQL> INSERT INTO T_P VALUES (1, 'A');


已創(chuàng)建1行。


SQL> INSERT INTO T_P VALUES (2, 'B');


已創(chuàng)建1行。


SQL> INSERT INTO T_C VALUES (1, 1, 'A');


已創(chuàng)建1行。


SQL> COMMIT;


提交完成。


SQL標(biāo)準(zhǔn)定義的RESTRICT操作其實和NO ACTION操作十分類似。不同之處在于,RESTRICT的檢查在語句執(zhí)行之前,一旦發(fā)現(xiàn)主鍵被引用,就會報錯,阻止更新或刪除操作的執(zhí)行。
SQL> SELECT * FROM T_P;


?? ? ? ?ID NAME
---------- ------------------------------
?? ? ? ?1 A
?? ? ? ? 2 B


SQL> SELECT * FROM T_C;


?? ? ? ?ID ? ? ? ?FID NAME
---------- ---------- ------------------------------
?? ? ? ? 1 ? ? ? ? 1 A


SQL> UPDATE T_P SET ID = 3 WHERE ID = 1;
UPDATE T_P SET ID = 3 WHERE ID = 1
*
第1行出現(xiàn)錯誤:
ORA-02292:違反完整約束條件(YANGTK.FK_T_C) -已找到子記錄日志


對于上面這種情況,無論是NO ACTION還是RESTRICT,效果沒有什么差別,而對于下面的情況就不一樣了:
SQL> UPDATE T_P SET ID = ID - 1;


已更新2行。


SQL> SELECT * FROM T_P;


?? ? ? ?ID NAME
---------- ------------------------------
?? ? ? ?0 A
?? ? ? ? 1 B


SQL> UPDATE T_P SET ID = ID + 1;


已更新2行。


SQL> SELECT * FROM T_P;


?? ? ? ?ID NAME
---------- ------------------------------
?? ? ? ?1 A
?? ? ? ? 2 B


對于NO ACTION來說,約束的檢查發(fā)生在語句之后,所有上面的語句可以順利執(zhí)行,而對于RESTRICT而言,這個操作會直接報錯。
下面構(gòu)建一個RESTRICT操作的觸發(fā)器:
SQL> CREATE OR REPLACE TRIGGER T_P_RESTRICT
??2 ?BEFORE DELETE OR UPDATE OF ID ON T_P
??3 ?FOR EACH ROW
??4 ?WHEN (NVL(NEW.ID, -1) != NVL(OLD.ID, -1))
??5 ?DECLARE
??6 ? V_STR VARCHAR2(32767);
??7 ? V_COUNT NUMBER;
??8 ?BEGIN
??9 ? FOR I IN (SELECT OWNER, TABLE_NAME, CONSTRAINT_NAME
?10 ? ?FROM ALL_CONSTRAINTS
?11 ? ?WHERE CONSTRAINT_TYPE = 'R'
?12 ? ?AND R_OWNER = 'YANGTK'
?13 ? ?AND R_CONSTRAINT_NAME IN
?14 ? ? (SELECT CONSTRAINT_NAME FROM USER_CONSTRAINTS WHERE TABLE_NAME = 'T_P'))
?15 ? LOOP
?16 ? ?V_STR := 'SELECT COUNT(*) FROM ?' || I.TABLE_NAME || ' WHERE ';?
?17 ? ?FOR J IN (SELECT COLUMN_NAME FROM ALL_CONS_COLUMNS
?18 ? ? WHERE WNER = I.OWNER
?19 ? ? AND TABLE_NAME = I.TABLE_NAME
?20 ? ? AND CONSTRAINT_NAME = I.CONSTRAINT_NAME)
?21 ? ?LOOP
?22 ? ? V_STR := V_STR || J.COLUMN_NAME || ' = ' || :OLD.ID;
?23 ? ?END LOOP;
?24 ? ?EXECUTE IMMEDIATE V_STR INTO V_COUNT;
?25 ? ?IF V_COUNT > 0 THEN
?26 ? ? RAISE_APPLICATION_ERROR(-20001, '違反完整約束條件限制操作-已找到子記錄日志');
?27 ? ?END IF;
?28 ? END LOOP;
?29 ?END;
?30 ?/


觸發(fā)器已創(chuàng)建


SQL> SELECT * FROM T_P;


?? ? ? ?ID NAME
---------- ------------------------------
?? ? ? ?1 A
?? ? ? ? 2 B


SQL> SELECT * FROM T_C;


?? ? ? ?ID ? ? ? ?FID NAME
---------- ---------- ------------------------------
?? ? ? ? 1 ? ? ? ? 1 A


SQL> UPDATE T_P SET ID = ID - 1;
UPDATE T_P SET ID = ID - 1
?? ? ? ? ? ? ? ? ? *
第1行出現(xiàn)錯誤:
ORA-20001:違反完整約束條件限制操作-已找到子記錄日志
ORA-06512:在"YANGTK.T_P_RESTRICT", line 22
ORA-04088:觸發(fā)器'YANGTK.T_P_RESTRICT'執(zhí)行過程中出錯


這種方式可以實現(xiàn)RESTRICT操作,但是對于其他會話的外鍵的引用,RESTRICT操作是看不到的:
SQL> CONN YANGTK/YANGTK@YTK92
已連接。
SQL> SET SQLP 'SQL2> '
SQL2> INSERT INTO T_C VALUES (2, 2, 'B');


已創(chuàng)建1行。


在另一個會話插入一條參考主表ID為2的記錄,且不提交,這時在主表更新或刪除ID為2的記錄時,會被鎖住,RESTRICT操作不會起作用,因為這時看不到其他用戶未提交的修改:
SQL> DELETE T_P WHERE ID = 2;


而如果在第二個會話中提交事務(wù):
SQL2> COMMIT;


提交完成。


則RESTRICT操作會起作用,因為這時已經(jīng)提交,而當(dāng)前的會話是可以看到其他會話中已提交數(shù)據(jù)的:
DELETE T_P WHERE ID = 2
?? ? ? ? ? ? ? ? ? *
第1行出現(xiàn)錯誤:
ORA-20001:違反完整約束條件限制操作-已找到子記錄日志
ORA-06512:在"YANGTK.T_P_RESTRICT", line 22
ORA-04088:觸發(fā)器'YANGTK.T_P_RESTRICT'執(zhí)行過程中出錯




SQL>


總結(jié)

以上是生活随笔為你收集整理的小议Oracle外键约束修改行为的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。