主鍵約束自動建立索引問題


         約束用於確保數據庫數據的完整性,在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狀態。

 

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
 現在表中有兩條記錄,然后給它插主鍵為空或相同的值。
 
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
 
可以看到全部報錯,此時主鍵不能為空或重復
查看是否建立索引
 
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
                    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. 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM