2021年5月31日 星期一

9.6 Constraint

在關聯式資料庫的架構底下,有可能 Table 之間的資料都具有相依性,為了避免 Table 之間的資料錯亂,因此產生了 Constraint 這個東西來約束 Table 的資料,例如在 HR 這個使用者底下,主要的 Table 為 employees ,其它如 departmemts 、 jobs 等 Table 都與其有相關性,例如 employees 的 department_id 這個欄位是關聯到 departments 的 department_id 欄位 、 job_id 欄位則是關聯到 jobs 的 job_id :


Constraint 的種類總共有 Primary Key 、 Foreign Key 、 Not Null 、 Check ,以及 Unique 五種:


  • Primary Key: 

具有 Unique 與 Not Null 的特性, Table 所建立的 Primary Key 可以是單一欄位或者是多個欄位組合起來,作為 Primary Key 的欄位資料必須是唯一值且不可為 Null 。


  • Foreign Key: 

用來參照其它 Table 的欄位資料所用, Foreign Key 所參照的 Table 欄位必須是 Primary Key 或者是具有 Unique 屬性,被參照具有 Primary (Unique) Key 的 Table 我們稱作 Parent Table ;而建立 Foreign Key 用來參照別人的 Table 我們稱作 Child Table 。作為 Foreign Key 欄位的資料必須是所參照 Primary Key (或 Unique Key) 裡面的資料,否則會出現 ORA-02291: integrity constraint violated - parent key not found 的錯誤,例如 sales 具有 Primary Key (prod_id) ,而 sales_items 則是建立 Foreign Key (prod_id) 關聯到 sales:

如果在 sales_itmes insert 一筆 sales 不存在的資料就會報 ORA-02291 錯誤:


同樣的如果在 Parent Table delete 一筆資料,但此筆資料正存在 Child Table ,此時會報 ORA-02292: integrity constraint violated - child record found:


若是 Foreign Key 建立時賦予 on delete cascade 屬性,則 Parent Table 刪除資料的同時也會把 Child Table 相對應的資料刪除,此時不會有 ORA-02292 錯誤:


最後需要注意的是, Child Table 所用來當 Foreign Key 的欄位必須要建立 Index ,否則在 Table 資料的更新過程中,容易因為獲取不到 SSX lock (Share Row-eXclusive: Mode 5) 從而產生等待。上述範例中, SALES_ITEMS 這個 Child Table 的 prod_id 欄位作為 Foreign Key ,此時就必須為 SALES_ITEMS 的 prod_id 建立 Index 。


  • Not Null Constraint:

在 Table 的欄位設定為 Not Null 屬性時,就會幫它加上一個 Not Null Constraint ,表示此欄位的資料不可為 Null 。


  • Check Constraint:

用來檢查 Table 的資料必須符合某些條件,否則不能新增進來。例如限制 sales_items 的 uni_price 欄位值必須大於 0 ,在新增一筆 -100 的資料時便會出現 ORA-02290: check constraint violated 的錯誤:


  • Unique Constraint:

用來檢查欄位的資料是否為唯一值。在建立 Unique Index 的同時會自動添加上 Unique Constraint 。


Constraint 的建立可以在 Create Table 的時候就一併建上,或者是之後用 alter table 的命令來建立:

SQL> CREATE TABLE sales( prod_id NUMBER ,cust_id NUMBER,time_id DATE,

 CONSTRAINT sales_pk PRIMARY KEY(prod_id));

    (在 create table 的時候就建立 primary key)


SQL> alter table sales add constraint c1 unique(prod_id);

    (新建 unique constraint)


SQL> alter table sales_items add constraints sales_items_fk FOREIGN KEY(prod_id) REFERENCES sales(prod_id);

    (新建 foreign key)


除非是在 Table 建立的時候就已經把 Constraint 建好,否則在新增 Constraint 的時候 Table 可能已經有資料了,因此 Constraint 本身的狀態可以分為 enable / disable 與 validate / novalidate 兩種。 


enable / disable 的狀態表示此 Constraint 是否要檢查新增進來的資料, enable 表示檢查新增的資料 ; disable 表示不檢查。 validate / novalidate 表示 Constraint 是否檢查已經存在 Table 上面的資料, validate 表示在 Constraint 新增的同時,檢查 Table 已存在的資料是否符合此 Constraint 的設定,如果已經有資料違反此新增的規則就無法建立,此時必須使用 novalidate 不檢查已存在的資料來新增:


Constraint 建立的預設選項都是 enable validate 。


如果要修改 Constraint 屬性必須使用 alter table 命令來修改:

SQL> alter table sales_items enable novalidate constraint pri_check;

    (將 constraint pri_check 改為 enable novalidate)


SQL> alter table sales_items disable validate constraint sales_items_fk;

    (將 constraint sales_items_fk 改為 disable validate)


要得知 Constraint 的資訊可以從 dba_constraints 或是 user_constraints 來查詢:


其中的 constraint_type 代表:

  • P: Primary Key

  • R: Foreign Key

  • U: Unique Key

  • C: Check 或是 Not Null Constraint


藉由 Constraint 的設定可以確保 Table 之間的資料維持一致性,也可以避免輸入錯誤的資料進到 Table 中,對於關聯式資料庫來說是一個重要的角色。




沒有留言:

張貼留言