數據完整性約束
數據完整性約束
數據完整性約束指的是為了防止不符合規範的數據進入資料庫,在用戶對數據進行插入、修改、刪除等操作時,DBMS自動按照一定的約束條件對數據進行監測,使不符合規範的數據不能進入資料庫,以確保資料庫中存儲的數據正確、有效、相容。
該詞為計算機學科資料庫技術術語 |
數據完整性約束是一組完整性規則的集合。它定義了數據模型必須遵守的語義約束,也規定了根據數據模型所構建的資料庫中數據內部及其數據相互間聯繫所必須滿足的語義約束。 |
完整性約束是資料庫系統必須遵守的約束,他限定了根據數據模型所構建的資料庫的狀態以及狀態變化,以便維護資料庫中數據的正確性、有效性和相容性。 |
1 數據的完整性
約束是用來確保數據的準確性和一致性。數據的完整性就是對數據的準確性和一致性的一種保證。
數據完整性(Data Integrity)是指數據的精確(Accuracy)和可靠性(Reliability)。
分為以下四類:
1) 實體完整性:規定表的每一行在表中是惟一的實體。
2) 域完整性:是指表中的列必須滿足某種特定的數據類型約束,其中約束又包括取值範圍、精度等規定。
4) 用戶定義的完整性:不同的關係資料庫系統根據其應用環境的不同,往往還需要一些特殊的約束條件。用戶定義的完整性即是針對某個特定關係資料庫的約束條件,它反映某一具體應用必須滿足的語義要求。
2 完整性約束的類型:
可分為三種類型:與表有關的約束、域(Domain)約束、斷言(Assertion)
1) 與表有關的約束:是表中定義的一種約束。可在列定義時定義該約束,此時稱為列約束,也可以在表定義時定義約束,此時稱為表約束。
2) 域(Domain)約束:在域定義中被定義的一種約束,它與在特定域中定義的任何列都有關係。
3) 斷言(Assertion):在斷言定義時定義的一種約束,它可以與一個或多個表進行關聯。
一、與表有關的約束:包括列約束(表約束+NOT NULL)和表約束(PRIMARY KEY、foreign key、check、UNIQUE)。
(1) not null(非空)約束:只用於定義列約束。
語法如下:
Colunm_name datatype | domain not null
實例:
create table Employee
(
emp_id int not null,
emp_name varchar(10) not null,
address varchar(40) ,
)
創建之後,如果往表Employee表中非空約束中插入空值,insert into Employee values(1,null,'neimeng')將會出錯。如下:
Msg 515, Level 16, State 2, Line 1
Cannot insert the value NULL into column 'emp_name', table 'Student.dbo.Employee';
column does not allow nulls. INSERT fails.
The statement has been terminated.
(2) unique(惟一)約束:用於指明創建惟一約束的列上的取值必須惟一。
語法如下:
Colunm_name datatype | domain unique
實例:
create table EmployeeInfo
(
emp_id int not null,
emp_name varchar(10) not null,
phone char(11) unique,
address varchar(40) ,
)
如下往EmployeeInfo插入數據時,如果兩條記錄的phone不惟一,
insert into EmployeeInfo values(1,'abcdwxc','neimeng','13612345678')
insert into EmployeeInfo values(2,'terry','neimeng','13612345678')
則會出現錯誤。如下:
(1 row(s) affected)
Msg 2627, Level 14, State 1, Line 2
Violation of UNIQUE KEY constraint 'UQ__EmployeeInfo__060DEAE8'. Cannot insert duplicate key in object 'dbo.EmployeeInfo'.
The statement has been terminated.
除了在定義列時添加unique約束外,也可以將unique約束作為表約束添加。即把它作為表定義的元素。
語法如下:
[CONSTRAINT constraint_name] unique (column1,column2,.....)
實例:
create table EmployeeInfo
(
emp_id int not null,
emp_name varchar(10) not null,
phone char(11)
address varchar(40) ,
constraint p_uniq unique(phone)
)
(3) primary key(主鍵)約束:用於定義基本表的主鍵,起惟一標識作用,其值不能為null,也不能重複,以此來保證實體的完整性。
語法如下:
Colunm_name datatype | domain primary key
實例:
drop table EmployeeInfo
create table EmployeeInfo
(
emp_id int primary key,
emp_name varchar(10) not null,
phone char(11),
address varchar(40) ,
)
如果向EmployeeInfo表插入的emp_id重複了或者插入時emp_id為null值,則會出錯。
可以在創建表時,創建主鍵約束,也可創建表完成以後,創建主鍵,例如:
alter table EmployeeInfo
add constraint e_prim primary key(emp_id)
primary key 與 unique的區別:
1.在一個表中,只能定義一個primary key約束,但可定義多個unique約束。
(4) foreign key(外鍵)約束:定義了一個表中數據與另一個表中的數據的聯繫。
foreign key約束指定某一個列或一組列作為外部鍵,其中包含外部鍵的表稱為子表,包含外部鍵所引用的主鍵的表稱為父表。系統保證,表在外部鍵上的取值要麼是父表中某一主鍵,要麼取空值,以此保證兩個表之間的連接,確保了實體的參照完整性。
語法如下:
Colunm_name datetype | domain references table_name(column)
[match full|partial|simple] //註:sqlserver不支持。
[referential triggered action]
說明:table_name為父表的表名,column為父表中與外鍵對應的主鍵值。
[match full|partial|simple]為可選子句,用於設置如何處理外鍵中的null值。
[referential triggered action]也為可選子句,用於設置更新、刪除外鍵列時的操作準則。
可以為表的一列或多列創建foreign key 約束,如果為多列創建 foreign key約束,將分別與主表中的相應主鍵相對應。
實例:
create table EmployeeInfo
(
emp_id int primary key,
emp_name varchar(10) not null,
account char(4) primary key,
phone char(11)
address varchar(40) ,
)
create table Emp_Sal
(
emp_id int , account CHAR(4) ,salary DECIMAL(5,1),
CONSTRAINT E_SAL FOREIGN KEY(emp_id,account) REFERENCES EmployeeInfo (emp_id,account))
)
也可以表創建以後添加到表上。如下:
create table Emp_Sal
(
emp_id int ,emp_name varchar(10) not null, account CHAR(4) ,salary DECIMAL(5,1),
)
alter table Emp_Sal
add CONSTRAINT E_SAL FOREIGN KEY(emp_id,account) REFERENCES EmployeeInfo (emp_id,account)
該外鍵的作用:確保表Emp_Sal的每個emp_id列都對應表EmployeeInfo中相應的emp_id。此時,表EmployeeInfo為父表,而表Emp_Sal為子表。子表的emp_id列參照父表的emp_id列。
如果想在子表的emp_id列插入一個值,首先父表的emp_id列必須存在,否則會插入失敗。如果想從父表的emp_id刪除一個值,則必須無刪除子表emp_id列中所有與之對應的值。
(注:foreign key 列上的取值可以取null)。
潛在問題:由於foreign key列上可以取空值,DBMS將跳過對foreign key約束的檢查,因此如果插入Emp_Sal如下數據:
insert into Emp_Sal values(6,null,null) 則插入到Emp_Sal中,但其主表的相關列卻不存在。
解決辦法:
(1)將聯合外鍵的列添加not null約束,但這限制了用戶的部分操作。
更新、刪除操作規則:
在刪除或更新有primary key值的行,且該值與子表的foreign key中一個或多個值相匹配時,會引起匹配完整性的喪失。
在foreign key創建語法中,提供了可選的on update和on delete子句,也就是上面的[referential triggered action]。可用此保持引用完整性。
on update / on delete
no action|cascade|restrict|set null|set default
no action:更新或刪除父表中的數據時,如果會使子表中的外鍵違反引用完整性,該動作將被禁止執行。不過在某些條件下,可出現暫時的,但在數據的最終狀態中,不能違反外鍵的引用完整性。
cascade: 當父表中被引用列的數據被更新或刪除時,子表中的相應的數據也被更新或刪除。
restrict:與no action規則基本相同,只是引用列中的數據永遠不能違反外鍵的引用完整性,暫時的也不行。
set default:當父表數據被更新或刪除時,子表中的數據被設置成默認值。前提是子表中的相應列設置有默認值。
(5) check(校驗)約束:用來檢查欄位值所允許的範圍。DBMS每當執行delete,insert或update語句時,都對這個約束過濾。如果為true,則執行。否則,取消執行並提示錯誤。
列定義語法如下:
Column datetype | domain check(search condition)
表約束語法如下:
constraint constraint_name check(search condition)
實例如下:
create table Emp_Sal
(
emp_id int , account CHAR(4) ,salary DECIMAL(5,1),
constraint validsal check(salary >=1000 and salary<=10000)
)
如果此時,再往表中插入如下語句則會出錯:(因為不滿足salary大於等於1000的約束。)
insert into Emp_Sal values(8,'12324343',800.0)
二、域約束:(sqlserver 不支持)
語法如下:
create domain domain_name as data type
[default default_value]
[constraint constraint_name] check(value condition expression)
例如:
create domain valid_no as int
constraint constraint_no check(value between 100 and 999)
然後創建表時,使用valid_no域。
create table TestDomain
(
emp_id valid_no,
emp_name varchar(10),
)
三、斷言約束:不必與特定的列綁定,可以理解為能應用於多個表的check約束,因此必須在表定義之外獨立創建斷言。
語法如下:
create assertion constraint_name
check search condition
例如:
create assertion name
check (Emp_Sal.emp_id in(select emp_id from EmployeeInfo where emp_name is not null)
添加斷言后,每當試圖添加或修改Emp_Sal表中的數據時,就對斷言中的搜索條件求值,如果為false,則取消執行,給出提示