禁用外鍵約束來解決輸入數據出錯的問題之解決方案三

第三種解決方案:采用Oracle 可延遲約束Deferable。

約束可以是deferrable或not deferrable(默認)。
not deferrable 約束在每一個DML語句后檢查;

deferrable 約束可以在每一個insert,delete,或update(即時模式)后立即檢查,或者在事務末尾檢查(延遲模式)

當沒有按特定順序執行數據加載時,這項功能特別有用——它允許先把數據載入子表,然后再裝入父表。

另一種用法是在加載不符合某個check約束的數據之后,對其進行適當的更新

語法如下:

[ [not] deferrable [initially {immediate | deferred} ] ]

或

[ [initially {immediate | deferred} ] [not] deferrable ]
  • deferrable介紹

deferrable的兩個選項區別

deferrable表示該約束是可延遲驗證的. 它有兩個選項:
Initially immediate(默認): 立即驗證, 執行完一個sql后就進行驗證;
Initially deferred: 延遲驗證, 當事務提交時或調用set constraint[s] immediate語句時才驗證.
區別是: 事務提交時驗證不通過, 則立即回滾事務; set constraint[s] immediate時只驗證, 不回滾事務.

not deferrable與deferrable區別
區別就在于: “立即驗證的可延遲約束” 是可以根據需要設置成 “延遲驗證的可延遲約束”的, 而“不可延遲驗證”是不能改變的.

  • deferrable實例

建表

create table test1(a number(1) constraint check_a check(a > 0) deferrable

                   initially immediate,

                   b number(1) constraint check_b check(b > 0) deferrable

                   initially deferred);

正常插入,沒問題

SQL> insert into test1 values(1, 1);

1 row inserted

檢驗立即驗證:數據不能插入

SQL> insert into test1 values(-1, 1);

insert into test1 values(-1, 1)

ORA-02290: 違反檢查約束條件 (MYHR.CHECK_A)

檢驗延遲驗證:可以執行

SQL> insert into test1 values(1, -1);

1 row inserted

SQL> select * from test1;

 A  B

-- --

 1  1

 1 -1

提交延遲驗證(commit):驗證失敗,自動回滾

SQL> commit;

 commit

 ORA-02091: 事務處理已回退

ORA-02290: 違反檢查約束條件 (MYHR.CHECK_B)

提交延遲驗證(set constraint immediate):驗證失敗,不回滾

SQL> insert into test1 values(1, -1);

1 row inserted

SQL> set constraint check_b immediate;

set constraint check_b immediate

ORA-02290: 違反檢查約束條件 (MYHR.CHECK_B)

或者將所有的約束做修改:alter session set constraints = immediate;

或者:set constraints all immediate;

將延遲驗證設置為立即驗證:則在插入時出錯

SQL> set constraint check_b immediate;

Constraints set

SQL> insert into test1 values(1,-1);

insert into test1 values(1,-1)

ORA-02290: 違反檢查約束條件 (MYHR.CHECK_B)
  • deferrable用途

物化視圖

物化視圖(快照),這是它的主要用途。這些視圖會使用延遲約束來進行視圖刷新。在刷新物化視圖的過程中,可能會破壞完整性,而且將不能逐句檢驗約束。但到執行COMMIT時,數據完整性就沒問題了,而且能滿足約束。沒有延遲約束,物化視圖的約束可能會使刷新過程不能成功進行。

級聯更新

當預測是否需要更新父/子關系中的主鍵時,它有助于級聯更新。看一下實際的例子:

SQL> create table t(tno number(10) constraint pk_t_tno primary key, tname varchar2(20));

SQL> create table s(sno number(10) constraint pk_s_tno primary key, sname varchar2(20), tno number(10));

SQL> alter table s add constraint fk_s_tno foreign key (tno) references t(tno);

SQL> insert into t values(1,'yuechaotian');

SQL> insert into t values(2,'tianyuechao');

SQL> commit;

SQL> insert into s values(1,'stu_1', 1);

SQL> insert into s values(2,'stu_2', 1);

SQL> commit;

SQL> update t set tno=22 where tno=2;

SQL> update t set tno=11 where tno=1;

update t set tno=11 where tno=1

ORA-02292: 違反完整約束條件 (MYHR.FK_S_TNO) - 已找到子記錄

SQL> select * from t;

        TNO TNAME

----------- --------------------

          1 yuechaotian

         22 tianyuechao


SQL> select *from s;

        SNO SNAME                        TNO

----------- -------------------- -----------

          1 stu_1                          1

          2 stu_2                          1 


SQL> rollback;

SQL> alter table s drop constraint fk_s_tno;

SQL> alter table s add constraint fk_s_tno foreign key (tno) references t(tno) deferrable initially immediate;
```
------------------
```
SQL> select * from t;

        TNO TNAME

----------- --------------------

          1 yuechaotian

          2 tianyuechao

SQL> select * from s;

        SNO SNAME                        TNO

----------- -------------------- -----------

          1 stu_1                          1

          2 stu_2                          1
 
```
-----------
```
SQL> set constraint fk_s_tno deferred;

Constraints set

SQL> update t set tno=22 where tno=2;

SQL> update t set tno=11 where tno=1;

SQL> update s set tno = 11 where tno = 1;

SQL> commit;
```
----------------
```
SQL> select * from t;

        TNO TNAME

----------- --------------------

         11 yuechaotian

         22 tianyuechao

SQL> select * from s;

        SNO SNAME                        TNO

----------- -------------------- -----------

          1 stu_1                         11

          2 stu_2                         11
```
--------------------
``` 
SQL> select a.constraint_name, a.deferrable, a.deferred from user_constraints a where a.constraint_name like '%TNO%';

CONSTRAINT_NAME                DEFERRABLE     DEFERRED

------------------------------ -------------- ---------

FK_S_TNO                       DEFERRABLE     IMMEDIATE

PK_S_TNO                       NOT DEFERRABLE IMMEDIATE

PK_T_TNO                       NOT DEFERRABLE IMMEDIATE

```
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容