Constraint基礎(chǔ)概念
?
??? 一直對(duì)constraint的概念比較模糊,沒(méi)有系統(tǒng)得學(xué)習(xí)過(guò)一次。這次專門來(lái)學(xué)習(xí)一下這方面的內(nèi)容。其實(shí)如果不用到REF constraint的話,這部分還是比較簡(jiǎn)單明晰的,關(guān)鍵是要記住創(chuàng)建和修改constraint的幾個(gè)語(yǔ)法,這很重要。
首先來(lái)看一下《SQL Reference》中對(duì)于Constraint的說(shuō)明:
?
?
??? 下面說(shuō)一下我的認(rèn)識(shí):
?
1、Constraints的目的:
?
????? 設(shè)立Constraint就是為了讓數(shù)據(jù)滿足某些規(guī)則。
2、Constraint的類型:
?
????? not null??? (不能為空)
????? unique????? (值必須唯一)
????? primary key (not null + unique)
????? goreign key (該表值必須在外鍵表中存在)
????? check?????? (自己加的條件)
????? unique????? (值必須唯一)
????? primary key (not null + unique)
????? goreign key (該表值必須在外鍵表中存在)
????? check?????? (自己加的條件)
????? ref???????? (不熟)
??? 注:Constraints不但可以建立在Table上,也可以建立在View上。
3、Constraint的狀態(tài):
?
????? ① Deferrable
????? 該參數(shù)用于指定是否可以是同set語(yǔ)句來(lái)進(jìn)行臨時(shí)控制constraint,時(shí)約束在commit時(shí)才生效
????? DEFERRABLE:可以使用set constraint字句
????? NOT DEFERRABLE:不可以使用set constraint字句(默認(rèn))
?
????? ② Initially
????? 該參數(shù)用于建立默認(rèn)的DEFERRABLE類型約束
????? INITIALLY一般都要和IMMEDIATE、DEFERRED一起使用
????? INITIALLY IMMEDIATE:在執(zhí)行SQL時(shí)違反約束即報(bào)錯(cuò)(默認(rèn))
????? INITIALLY DEFERRED:在提交時(shí)才報(bào)錯(cuò)
?
????? ③ Validate | NoValidate
????? 該參數(shù)一般與Enabled和Disabled屬性搭配使用
?
????? ④ Enable
????? 該參數(shù)確認(rèn)約束應(yīng)用于數(shù)據(jù)
????? ENABLE VALIDATE:將驗(yàn)證已經(jīng)存在的和之后的操作是否符合約束(默認(rèn))
????? ENABLE NOVALIDATE:不驗(yàn)證已經(jīng)存在的數(shù)據(jù),但對(duì)之后進(jìn)行的操作有效
?
????? ⑤ Disable
????? 該參數(shù)使約束失效
????? DISABLE VALIDATE:約束失效標(biāo)注,可用于暫時(shí)導(dǎo)入大量數(shù)據(jù)時(shí),不進(jìn)行索引更新
????? DISABLE NOVALIDATE:約束失效,并不保證約束是否正確,即不保證已有數(shù)據(jù)滿足約束(默認(rèn))
?
????? ⑥ Rely
????? Rely和Norely只能用在 ALTER TABLE MODIFY constraint 語(yǔ)句中
????? Rely:告訴Oracle,不必對(duì)NOVALIDATE模式的約束的數(shù)據(jù)進(jìn)行信任,即需要檢驗(yàn)以前的數(shù)據(jù)
????? (這個(gè)沒(méi)用過(guò),實(shí)在搞不準(zhǔn)確切含義,還是把文檔的內(nèi)容直接放上來(lái))
?
?
4、set語(yǔ)句
?
?
?
?
?
----------------------------------------------------------------------------------------------------
轉(zhuǎn)一篇Constraint的文章
----------------------------------------------------------------------------------------------------
?
?
constraints 三個(gè)需要注意的地方
?
1. deferrable
?
一個(gè)constraint如果被定義成deferrable那么這個(gè)constraints可以在deferred和imediate兩種狀態(tài)相互轉(zhuǎn)換。deferred只在transaction中有效,也就是只可以在transaction過(guò)程中使constraint失效,但如果transaction commit的話,transaction會(huì)變成immediate。
?
SQL> create table cons_parent (id number(10),name varchar2(10));
Table created.
Table created.
?
SQL> create table cons_child (id number(10),name varchar2(10));
Table created.
Table created.
?
SQL> alter table cons_parent add primary key (id);
Table altered.
Table altered.
?
SQL>alter table cons_child add constraints chi_fk_par foreign key (id)
2?? references cons_parent(id);
Table altered.
2?? references cons_parent(id);
Table altered.
?
SQL> alter table cons_child add constraints chi_fk_par foreign key (id)
2 references cons_parent(id);
Table altered.
2 references cons_parent(id);
Table altered.
?
一個(gè)constraint默認(rèn)是NOT DEFERRABLE的
?
SQL> select constraint_name||' '||deferrable from all_constraints
2??? where constraint_name='CHI_FK_PAR';
2??? where constraint_name='CHI_FK_PAR';
?
CONSTRAINT_NAME||''||DEFERRABLE
---------------------------------------------
CHI_FK_PAR NOT DEFERRABLE
---------------------------------------------
CHI_FK_PAR NOT DEFERRABLE
?
NOT DEFERRABLE的不能在deferred和imediate兩種狀態(tài)相互轉(zhuǎn)換
?
SQL> set constraints chi_fk_par deferred;
SET constraints chi_fk_par deferred
*
ERROR at line 1:
ORA-02447: cannot defer a constraint that is not deferrable
SET constraints chi_fk_par deferred
*
ERROR at line 1:
ORA-02447: cannot defer a constraint that is not deferrable
?
SQL> alter table cons_child drop constraints chi_fk_par;
Table altered.
Table altered.
?
SQL> alter table cons_child add constraints chi_fk_par foreign key (id)
2??? references cons_parent(id) deferrable;
Table altered.
2??? references cons_parent(id) deferrable;
Table altered.
?
SQL> select constraint_name||' '||deferrable from all_constraints
2??? where constraint_name='CHI_FK_PAR';
2??? where constraint_name='CHI_FK_PAR';
?
CONSTRAINT_NAME||''||DEFERRABLE
---------------------------------------------
CHI_FK_PAR DEFERRABLE
---------------------------------------------
CHI_FK_PAR DEFERRABLE
?
一個(gè)constraint如果被定義成deferrable那么這個(gè)constraints可以在deferred和imediate兩種狀態(tài)相互轉(zhuǎn)換
?
SQL> set constraints chi_fk_par immediate;
Constraint set.
Constraint set.
?
SQL> insert into cons_child values (2,'llll')
insert into cons_child values (2,'llll')
*
ERROR at line 1:
ORA-02291: integrity constraint (SYSTEM.CHI_FK_PAR) violated - parent key not found
insert into cons_child values (2,'llll')
*
ERROR at line 1:
ORA-02291: integrity constraint (SYSTEM.CHI_FK_PAR) violated - parent key not found
?
SQL> set constraints chi_fk_par deferred;
Constraint set.
Constraint set.
?
SQL> insert into cons_child values (2,'llll');
1 row created.
1 row created.
?
SQL> set constraints chi_fk_par immediate;
SET constraints chi_fk_par immediate
*
ERROR at line 1:
ORA-02291: integrity constraint (SYSTEM.CHI_FK_PAR) violated - parent key not found
SET constraints chi_fk_par immediate
*
ERROR at line 1:
ORA-02291: integrity constraint (SYSTEM.CHI_FK_PAR) violated - parent key not found
?
deferred只在transaction中有效,也就是只可以在transaction過(guò)程中使constraint失效,但如果transaction commit的話,transaction會(huì)變成immediate。
?
SQL> commit;
commit
*
ERROR at line 1:
ORA-02091: transaction rolled back
ORA-02291: integrity constraint (SYSTEM.CHI_FK_PAR) violated - parent key not found
deferrable會(huì)影響CBO的計(jì)劃,并且正常情況下沒(méi)有應(yīng)用的必要,所以建議不要修改,而用系統(tǒng)默認(rèn)的non deferrable
commit
*
ERROR at line 1:
ORA-02091: transaction rolled back
ORA-02291: integrity constraint (SYSTEM.CHI_FK_PAR) violated - parent key not found
deferrable會(huì)影響CBO的計(jì)劃,并且正常情況下沒(méi)有應(yīng)用的必要,所以建議不要修改,而用系統(tǒng)默認(rèn)的non deferrable
?
2. enable/disable validate/novalidate
?
enable/disable對(duì)未來(lái)的數(shù)據(jù)有約束/無(wú)約束。
?
validate/novalidate對(duì)已有的數(shù)據(jù)有約束/無(wú)約束。
?
如果加約束到一個(gè)大表,那么ORACLE會(huì)LOCK這個(gè)表,然后SCAN所有數(shù)據(jù),來(lái)判斷是否符合CONSTRAINT的要求,在繁忙的系統(tǒng)里顯然是不合適的。所以用enable novalidate比較合適,因?yàn)镺RACLE僅僅會(huì)LOCK表一小段時(shí)間來(lái)建立CONSTRAINT,當(dāng)CONSTRAINT建立后再VALIDATE,這時(shí)檢驗(yàn)數(shù)據(jù)是不會(huì)LOCK表的。
?
這方面很多書上都有例子,就不在這里累述了
?
3.REFERENCE 讓人疑惑的地方
?
SQL>? create table wwm_father (id number,name varchar2(10),primary key (id,name))
Table created.
Table created.
?
SQL> create table wwm_child (id number,name varchar2(10),
2??? foreign key (id,name) references wwm_father on delete set null);
Table created.
2??? foreign key (id,name) references wwm_father on delete set null);
Table created.
?
SQL> insert into wwm_father values (6,'wwm');
1 row created.
1 row created.
?
SQL> insret into wwm_child values (6,'fff');
SP2-0734: unknown command beginning "insret int..." - rest of line ignored.
SP2-0734: unknown command beginning "insret int..." - rest of line ignored.
?
可以看出,REFERENCE是起作用的。但下面就有點(diǎn)讓人疑惑了,似乎ORACLE不用該用這種策略來(lái)做,
?
SQL> insert into wwm_child values (6,null);
1 row created.
1 row created.
?
SQL> insert into wwm_child values(null,'lll');
1 row created.
1 row created.
?
SQL> insert into wwm_child values (null,null);
1 row created.
1 row created.
?
SQL> select * from wwm_father;
?
ID NAME
---------- --------------------
6 wwm
---------- --------------------
6 wwm
?
SQL> select * from wwm_child;
?
ID NAME
---------- --------------------
6
lll
---------- --------------------
6
lll
?
SQL> select count(*) from wwm_child;
?
COUNT(*)
----------
3
----------
3
?
可見(jiàn),如果向CHILD表插入NULL的話,ORACLE默認(rèn)認(rèn)為NULL是匹配FATHER表里相關(guān)的REFERENCE的字段內(nèi)容的。因此FOREIGN KEY的COLUMN大家就需要認(rèn)真考慮是否要設(shè)置成NOT NULL了
?