約束用於確保數據庫數據的完整性,在oracle 數據庫中,可以使用約束,觸發器和應用代碼(過程,函數)3種方法實現數據完整性,這3種方法中,因為約束易於維護,並且具有最好的性能,所以實現數據完整性首選約束.
一.約束分類
1.Not null: 確保字段值不能為空。
2.Unique: 確保字段值唯一性,但不阻止多個空值的插入。
3.Primary key:
最常用的約束(主鍵約束),主鍵約束的列值不僅不能重復,也不能為NULL,注意一張表最多只能有一個主鍵約束,當定義主鍵約束后oracle自動建立一個以主鍵為關鍵字段的索引。
4.Foreign key: 定義了主從表之間的關系,foreign要定義在從表上,但主表必須具有主鍵約束或唯一約束,當定義froeign key后外部鍵列的數據必須在主表的主鍵列中存在,或者為NULL。
5.Check: 用於強制表行數據必須滿足的條件,如工資表,工人工資必須在2000-5000之間。
二.約束狀態
enable validate:是默認,新舊數據同時滿足約束規則
enable novalidate:舊數據可以不滿足,檢新插入的數據要滿足約束
disable validate:不允許在表上執行任何DML操作,主要用在分區表,對於主鍵和唯一約事,會刪除相應的唯一索引,但約束狀態任可用
disable novalidate數據可不滿足約束規則,對於主鍵和唯一約事,會刪除相應的唯一索引
三.建立主鍵約束產生索引
檢驗當為一個表建立主鍵索引時后,這個字段是否滿足約束非空,唯一性,而且自動建立一個索引,並查看當把約束狀態關閉再次插入相同的記錄后,是否還能把把約束設為enable validate狀態。
檢驗當為一個表建立主鍵索引時后,這個字段是否滿足約束非空,唯一性,而且自動建立一個索引,並查看當把約束狀態關閉再次插入相同的記錄后,是否還能把把約束設為enable validate狀態。
SQL> create table t(i number constraint pk_i primary key,v number);
SQL> insert into t values(1,2);
SQL> insert into t values(3,4);
SQL> commit;
SQL> select * from t;
I V
---------- ----------
1 2
3 4
現在表中有兩條記錄,然后給它插主鍵為空或相同的值。
---------- ----------
1 2
3 4
現在表中有兩條記錄,然后給它插主鍵為空或相同的值。
SQL> insert into t values('',10);
ERROR at line 1: ORA-01400: cannot insert NULL into ("Y"."T"."I")
SQL> insert into t values(1,10);
insert into t values(1,10)
*
ERROR at line 1:
ORA-00001: unique constraint (SYS.PK_I) violated
insert into t values(1,10)
*
ERROR at line 1:
ORA-00001: unique constraint (SYS.PK_I) violated
可以看到全部報錯,此時主鍵不能為空或重復
查看是否建立索引
SQL> select index_name from user_indexes;
INDEX_NAME
------------------------------
PK_I
把約束關閉再次做同樣的操用
SQL> alter table t disable novalidate constraint pk_i;
Table altered.
SQL> insert into t values('',10);
1 row created.
SQL> insert into t values(1,10);
1 row created.
SQL> commit;
Commit complete.
SQL> select * from t;
I V
---------- ----------
1 2
3 4
1 10
---------- ----------
1 2
3 4
1 10
10
SQL> select index_name from user_indexes;
no rows selected
可見當把約束關閉后就可以何意給表插數據了,而具索引也自動刪除了。
現在激活約束
SQL> alter table t enable validate constraint pk_i;
alter table t enable validate constraint pk_i ERROR at line 1: ORA-02437: cannot validate (SYS.PK_I) - primary key violated
因為表中主鍵有相同的值所以不能恢復到enable validate狀態了
再次測試回復到enable novalidate
SQL> alter table t enable novalidate constraint pk_i;
alter table t enable validate constraint pk_i ERROR at line 1: ORA-02437: cannot validate (SYS.PK_I) - primary key violated
也失敗了,
enable novalidate不檢查舊數據所以應該還能恢復到enable novalidate,但為什么不行呢?因為在執行命令時,會產生唯一性索引(對pk_i),但對表中pk_i列已經有了重復的值,無法建立唯一性索引。
要想恢復到enable novalidate必須建立主鍵索引(關閉約束時自動刪除的那個索引,非唯一)如下:
SQL> create index pk_i on t(i);
Index created.
索引的默認類型是非唯一,非壓縮,非反向鍵B*樹索引。
然后恢復到enable disvalidate,以后再插數據不能為空,主鍵也不能重復了.
SQL> alter table t enable novalidate constraint pk_i;
Table altered.
SQL> insert into t values(1,14);
insert into t values(1,14) ERROR at line 1: ORA-00001: unique constraint (SYS.PK_I) violated
四.修正約束數據
當給一個表作主鍵約束時,因為已存數據不滿足約束規則,會提示錯誤信息,些時必須對數據進行修正
要修正數據先找出不滿足約束的數據
如下表,有不滿足約束的數據
SQL> select * from t;
I V
---------- ------------------------
1 2
3 4
15 12
15 10
如果一個表數據量多可通過如下方法查找
SQL> alter table t drop constraint pk_i;
T
able altered.
SQL>conn y / 123
SQL> @$ORACLE_HOME/rdbms/admin/utlexcpt.sql
Table created.
SQL> alter table t add constraint pk_i primary key (i) exceptions into exceptions;
SQL>select * from t where rowid in (select row_id from exceptions) ;
I V
---------- ------------------------
15 12
15 10
找到了重復的記錄
修正
SQL>update t set i=10 where v=12;
SQL> select * from t;
I V
---------- ----------
1 2
3 4
10 12
15 10
再建主鍵約束
SQL>alter table t add constraint pk_i primary key (i) ;
Table altered.