(一)約束的概念
在Oracle中,可以通過設置約束來防止無效數據進入表中。Oracle一共有5種約束:
- 主鍵約束(primary key)
- 外鍵約束(foreign key)
- 唯一性約束(unique)
- 非空約束(not null)
- 檢查約束(check)
(1)主鍵約束
--主鍵約束可以定義在一列或多列上,值具有唯一性、非空性;
--在一個表上只能定義一個主鍵約束;
--Oracle會自定在主鍵約束的列上創建唯一性索引,可以指定唯一性索引的位置及存儲參數。
(2)外鍵約束
--外鍵約束列的取值來源於參照表(父表)的參照列的值,或者空值;
--定義外鍵約束的列只能參照父表的主鍵約束列和唯一性約束列;
--父表與子表必須在同一個數據庫中。
(3)唯一性約束
--可定義在一列或多列上,列的取值必須唯一;
--如果在某些列上定義了唯一性約束,而沒有定義非空約束,那么在這些列上可以出現多個空值;
--Oracle會自定在主鍵約束的列上創建唯一性索引,可以指定唯一性索引的位置及存儲參數。
(4)非空約束
--只能定義在列上;
--在同一個表中可定義多個非空約束。
(5)檢查約束
--檢查約束用來限制列的取值范圍,其表達式必須引用相應列,表達式的計算結果是一個布爾值;
--一個列可以定義多個檢查約束
(二)列級約束與表級約束
列級約束是對某一個特定列的約束,包含在列的定義中,直接跟在其它定義之后,不需要指出列名。其語法為:
column_definition [CONSTRAINT constraint_name] constraint_type ...
表級約束的定義與列的定義相互獨立,通常用於多列組合的約束,定義表級約束要指出約束的名稱。其語法為:
[CONSTRAINT constraint_name] constraint_type(column1,[column2...]);
需要注意的是,除了非空約束只能定義列級約束外,其他的均可定義列級/表級約束。
(三)約束的狀態
根據在數據插入、更新時是否對數據進行約束檢查,約束狀態分為激活狀態(ENABLE)和禁用狀態(DISABLE);
根據是否對表中已有數據進行約束檢查,約束狀態分為驗證狀態(VALIDATE)和非驗證狀態(NOVALIDATE);
組合之后,一共有四種約束狀態:
| 約束狀態 |
定義 |
特點 |
| 激活驗證狀態 (ENABLE VALIDATE) |
激活約束且約束檢查已有數據 | 對表中已有數據進行檢查,對后續插入、更新的數據也會進行檢查 |
| 激活非驗證狀態 (ENABLE NOVALIDATE) |
激活約束但是不檢查表中已存在的數據 | 不檢查目前表中已經存在的數據,但會檢查后續插入、更新的數據 |
| 禁用驗證狀態 (DISABLE VALIDATE) |
不激活約束但是會去檢查表中已經存在的數據 | Oracle不允許進行任何DML(insert/update/delete)操作,因為操作無法得到約束的檢查。表處於只讀模式 |
| 禁用非驗證狀態 (DISABLE NOVALIDATE) |
不激活驗證且不檢查表中已有的數據 | 不會對表中數據進行約束檢查,也不會對新插入的數據進行約束檢查 |
(四)創建約束
(1)創建列級約束
創建列級約束的語法為:
INITIALLYCONSTRAINT constraint_name --約束名 [ --選擇5中約束類型 [NOT] NULL | [UNIQUE] | [PRIMARY KEY] | [CHECK (condition)] | [REFERENCES [schema.]object[(column)] [ON DELETE CASCADE | SET NULL]] ] [ --是否延遲約束檢查 [NOT DEFERRABLE] | [DEFERRABLE [INITIALLY IMMEDIATE | DEFERRED]] ] [ENABLE | DISABLE] --定義約束檢查的類型 [VALIDATE | NOVALIDATE ] [USING INDEX index_clause] --約束上索引的定義(主鍵約束與唯一性約束) [EXCEPTIONS INTO [schema.]table] --違反約束的數據的存儲方式
參數說明:
--cinstraint_name:約束名,如果沒有為約束命名,oracle將自動為約束命名,命名樣式為SYS_Cn,n是數據庫對象的唯一編號;
--ON DELETE CASCADE:定義級聯刪除的外鍵約束;
--ON DELETE SET NULL:定義置空刪除的晚間約束;
--NOT DEFERRABLE:約束不可延遲;
--DEFERRABLE:約束可以延遲;
--INITIALLY IMMEDIATE:可延遲約束的立即檢查;
--DEFERRED:可延遲約束的延遲檢查;
--USING INDEX index_clause:創建 唯一性索引的參數設置(存在與主鍵約束、唯一性約束);
--EXCEPTIONS INTO:將違反約束的記錄保存到表中。
(2)定義表級約束
列級約束是定義在列上的,如果需要在多個列上定義約束,則需采用表級約束,表級約束語法如下:
.INITIALLYCONSTRAINT constraint_name --約束名 [ --選擇4種約束類型,非空約束只能定義在列上 [UNIQUE(column1[,column2…])] | [PRIMARY KEY(column1[,column2…])] | [CHECK (condition)] | [FOREIGN KEY (column1[,column2…]) --外鍵約束需要指出要約束的列,與列級約束有較大區別
REFERENCES [schema.]object[(column1[,column2…])] [ON DELETE CASCADE | SET NULL]] ] [ --是否延遲約束檢查 [NOT DEFERRABLE] | [DEFERRABLE [INITIALLY IMMEDIATE | DEFERRED]] ] [ENABLE | DISABLE] --定義約束檢查的類型 [VALIDATE | NOVALIDATE ] [USING INDEX index_clause] --約束上索引的定義(主鍵約束與唯一性約束) [EXCEPTIONS INTO [schema.]table] --違反約束的數據的存儲方式
(五)添加、修改、重命名、刪除約束
(1)添加約束
語法為:
ALTER TABLE table_name ADD [CONSTRAINT constraint_name] constraint_type(column1[,column2...]) [constraint_parameters];
例子1.添加約束
--創建表books create table books ( id number(6), title varchar2(20), isbn number(20), auther varchar(10), price number(6,2), discribe varchar2(1000), pid number ); Table created --創建表publish(用來輔助books創建外鍵約束) create table publish ( pid number primary key, name varchar2(20) ); Table created --添加主鍵約束 SQL> alter table books add constraint books_pk primary key (id); Table altered --添加外鍵約束 --需要注意,參照的父表的列需要是主鍵約束列或唯一性約束列
--主要注意,外鍵約束的references帶‘s’ SQL> alter table books add constraint books_fk foreign key (pid) references publish(pid); Table altered --創建唯一性約束 SQL> alter table books add constraint books_unique unique (title); Table altered --創建檢查約束 SQL> alter table books add constraint books_check check (price > 0); Table altered --需要特別注意,非空約束只能使用modify來創建/刪除 ,不能使用add方式 --1.創建非空約束 SQL> alter table books modify auther not null; Table altered --2.刪除非空約束 SQL> alter table books modify auther null; Table altered
(2)修改約束
可以使用ALTER TABLE … MODIFY修改約束參數,語法為:
ALTER TABLE table_name MODIFY [CONSTRAINT constraint_name] | [PRIMARY KEY] | [UNIQUE(column1[,column2,...])] --主鍵約束和唯一性約束可以通過約束類型來修改 [constraint_parameters]
例子2.修改約束
--修改檢查約束,將其置為不檢查表中已有數據 SQL> alter table books modify constraint books_check novalidate; Table altered --使主鍵約束不可用 SQL> alter table books modify primary key disable; Table altered
(3)重命名約束
可以使用ALTER TABLE … RENAME…來重命名約束,語法為:
ALTER TABLE table_name RENAME CONSTRAINT old_constrain_name TO new_constraint_name;
(4)刪除約束
可以使用ALTER TABLE … DROP …來刪除約束,語法為:
ALTER TABLE table_name DROP [CONSTRAINT constraint_name] | [PRIMARY KEY] | [UNIQUE (column1 [,column2,...])] [CASCADE] [KEEP | DROP INDEX]
對於刪除約束,需要注意:
1.可以通過約束名稱來刪除約束,對於主鍵約束和唯一性約束,也可以指定約束的類型來刪除約束;
2.如果要刪除的主鍵約束或唯一性約束已經被子表中的外鍵約束引用,需要加CASCADE關鍵字,刪除子表中的外鍵約束;
3.在刪除主鍵約束/唯一性約束時,如果要保留主鍵約束/唯一性約束創建時生成的唯一性索引,則需要使用KEEP關鍵字。
圖、books與publish的關系
例子3.刪除主鍵約束
--根據上圖,我們發現books的外鍵引用了publish的主鍵,如果直接刪除,會報錯,只有加了cascade后才能刪除主鍵約束
--刪除主鍵約束后才去看books表,對應的外鍵約束也被刪除了
SQL> alter table publish drop primary key; alter table publish drop primary key ORA-02273: 此唯一/主鍵已被某些外鍵引用 SQL> alter table publish drop primary key cascade; Table altered
(六)關於外鍵約束的數據刪除方式
假如兩個表之間存在外鍵約束的關系,在父表進行數據刪除時,子表的關聯數據如何處理?Oracle提供了3種方式。
(1)受限刪除【默認】,如果子表中有與父表關聯的記錄存在,則不能刪除數據;
例子4.受限刪除無法刪除已經關聯的數據
create table table_a --父表 ( id number primary key, name varchar(20) ); create table table_b1 --子表 ( id number references table_a(id), --默認是受限刪除 country varchar2(30) ) SQL> insert into table_a values(1,'lijiaman'); 1 row inserted SQL> insert into table_b1 values(1,'test'); 1 row inserted SQL> commit; Commit complete SQL> delete table_a where id = 1; --子表有關聯數據,導致父表數據也無法刪除 delete table_a where id = 1 ORA-02292: 違反完整約束條件 (LIJIAMAN.SYS_C0013519) - 已找到子記錄 SQL> insert into table_a values(2,'fg'); 1 row inserted SQL> delete table_a where id = 2; --子表無關聯數據,父表數據可以刪除 1 row deleted SQL> commmit;
(2)級聯刪除,刪除父表數據的同時也會將外鍵關聯的子表的記錄刪除;
例子5.級聯刪除外鍵約束會刪除子表關聯數據
SQL> drop table table_b1; --刪除table_b1 Table dropped create table table_b2 --子表 ( id number references table_a(id) on delete cascade, --級聯刪除外鍵約束 country varchar2(30) ); SQL> insert into table_b2 values(1,'ch'); 1 row inserted SQL> select * from table_a ; --兩個表各有1行關聯數據 ID NAME ---------- -------------------- 1 lijiaman SQL> select * from table_b2; ID COUNTRY ---------- ------------------------------ 1 ch SQL> delete table_a where id = 1; --刪除父表數據,子表關聯數據也隨之刪除 1 row deleted SQL> commit; Commit complete SQL> select * from table_a; ID NAME ---------- -------------------- SQL> select * from table_b2; ID COUNTRY ---------- ------------------------------
(3)置空刪除,父表數據刪除后,子表中關聯記錄的外鍵約束的列值置為空;
例子6.置空刪除外鍵約束會將子表關聯記錄的外鍵列置為空值
create table table_b3 --子表 ( id number references table_a(id) on delete set null, --置空刪除外鍵約束 country varchar2(30) ); SQL> insert into table_a values(1,'adrci'); --往兩個表插入1行關聯數據 1 row inserted SQL> insert into table_b3 values(1,'srvctl'); 1 row inserted SQL> commit; Commit complete SQL> select * from table_a; ID NAME ---------- -------------------- 1 adrci SQL> select * from table_b3; ID COUNTRY ---------- ------------------------------ 1 srvctl SQL> delete table_a where id = 1; --刪除id=1的數據,父表整條記錄被刪除,子表僅置空了關聯數據的外鍵列值 1 row deleted SQL> select * from table_a; ID NAME ---------- -------------------- SQL> select * from table_b3; ID COUNTRY ---------- ------------------------------ srvctl
(七)與約束相關的數據字典
| 視圖名稱 | 說明 |
| DBA_CONSTRAINTS ALL_CONSTRAINTS USER_CONSTRAINTS |
包含數據庫中所有約束的定義信息; 包含當前用戶可以看到的所有約束的定義信息; 包含當前用戶擁有的約束的定義信息; |
| DBA_CONS_COLUMNS ALL_CONS_COLUMNS USER_CONS_COLUMNS |
記錄了約束列信息,DBA_ 、ALL_ 、USER_的用法與前面相同 |

