1. 程式人生 > >CHECK約束

CHECK約束

復合 一個 大於 weight 發生 eat rain 員工 數據表

CHECK約束會檢查輸入到記錄中的值是否滿足一個條件,如果不滿足這個條件則對數據庫做的修改不會成功。比如,一個人的年齡是不可能為負數的,一個人的入學日期不可能早於出生日期,出廠月份不可能大於12。可以在CHECK條件中使用任意有效的SQL表達式,CHECK約束對於插入、更新等任何對數據進行變化的操作都進行檢查。

在字段定義後添加CHECK 表達式就可以為這個字段添加CHECK約束,幾乎所有字段中都可以添加CHECK約束,也就是一張表中可以存在多個CHECK 約束。

下面的SQL語句創建了一張用於保存人員信息的表T_Person,其中字段FNumber 為人員編號,字段FName 為人員姓名,字段FAge為人員年齡,字段FWorkYear為人員工齡:


MYSQL,MSSQLServer,DB2:

CREATE TABLE T_Person (FNumber VARCHAR(20),FName VARCHAR(20),FAge INT CHECK(FAge >0),FWorkYear INT CHECK(FWorkYear>0))

Oracle:

CREATE TABLE T_Person (FNumber VARCHAR2(20),FName VARCHAR2(20),FAge NUMBER (10) CHECK(FAge >0),FWorkYear NUMBER (10) CHECK(FWorkYear>0))

一個人的年齡和工齡顯然不應該為負值的,所以為FAge和FWorkYear兩個字段增加了CHECK約束“FAge>0”和“FWeight>0”。表創建完畢後執行下面的SQL語句進行測試:


INSERT INTO T_Person(FNumber, FName, FAge, FWorkYear) VALUES("001","John",25,-3)

因為這裏將FWorkYear字段設置成了-3,這是違反“CHECK(FWorkYear>0)”這個CHECK約束,所以在數據庫中執行此SQL語句後數據庫會報出下面錯誤信息:

  • INSERT 語句與CHECK 約束"CKT_PersonFWorkY__24927208"沖突。該沖突發生於數據庫"demo",表"dbo.T_Person", column "FWorkYear"。

而執行下面的SQL語句則可以成功執行:


INSERT INTO T_Person(FNumber, FName, FAge, FWorkYear) VALUES("001","John",25,3)

除了可以在CHECK 約束中使用常量表達式之外,還可以在CHECK 約束中使用函數,比如人員編號長度要大於12,那麽就需要如下編寫建表語句:


MYSQL,DB2:

CREATE TABLE T_Person (FNumber VARCHAR(20) CHECK (LENGTH(FNumber)>12),FName VARCHAR(20),FAge INT CHECK(FAge >0),FWorkYear INT CHECK(FWorkYear>0))

MSSQLServer:

CREATE TABLE T_Person (FNumber VARCHAR(20) CHECK (LEN(FNumber)>12),FName VARCHAR(20),FAge INT CHECK(FAge >0),FWorkYear INT CHECK(FWorkYear>0))

Oracle:

CREATE TABLE T_Person (FNumber VARCHAR2(20) CHECK (LENGTH(FNumber)>12),FName VARCHAR2(20),FAge NUMBER (10) CHECK(FAge >0),FWorkYear NUMBER (10) CHECK(FWorkYear>12))

表創建完畢後執行下面的SQL語句進行測試:


INSERT INTO T_Person(FNumber, FName, FAge, FWorkYear) VALUES("001","John",25, 3)

因為這裏將FNumber字段設置成了"001",這是違反“CHECK(LENGTH(FNumber)>12)”這個CHECK約束的,所以在數據庫中執行此SQL語句後數據庫會報出下面錯誤信息:

  • INSERT 語句與CHECK 約束"CKT_PersonFNumbe__267ABA7A"沖突。該沖突發生於數據庫"demo",表"dbo.T_Person", column "FNumber"。

而執行下面的SQL語句則可以成功執行:


INSERT INTO T_Person(FNumber, FName, FAge, FWorkYear)VALUES("001001001001001","John",25,3)

這種直接在列定義中通過CHECK子句添加CHECK約束的方式的缺點是約束條件不能引用其他列。比如我們想約束“人員的工齡必須小於他的年齡”,那麽我們執行下面的SQL語句:


MYSQL,DB2:

CREATE TABLE T_Person (FNumber VARCHAR(20),FName VARCHAR(20),FAge INT,FWorkYear INT CHECK(FWorkYear< FAge))

MSSQLServer:

CREATE TABLE T_Person (FNumber VARCHAR(20),FName VARCHAR(20),FAge INT,FWorkYear INT CHECK(FWorkYear< FAge))

Oracle:

CREATE TABLE T_Person (FNumber VARCHAR2(20),FName VARCHAR2(20),FAge NUMBER (10),FWorkYear NUMBER (10) CHECK(FWorkYear< FAge))

執行這個SQL語句以後,數據庫會報出如下的錯誤信息:

表 "T_Person" 的列 "FWorkYear" 的列CHECK 約束引用了另一列。

出現這個錯誤的原因是因為在這種方式定義的CHECK子句中是不能引用其他列的,如果希望CHECK子句中的條件語句中使用其他列,則必須在CREATE TABLe 語句的末尾使用CONSTRAINT 關鍵字定義它。語法為:


CONSTRAINT 約束名 CHECK(約束條件)

重新編寫上述的SQL語句,如下:


MYSQL,DB2:

CREATE TABLE T_Person (FNumber VARCHAR(20),FName VARCHAR(20),FAge INT,FWorkYear INT,CONSTRAINT ck_1 CHECK(FWorkYear< FAge))

MSSQLServer:

CREATE TABLE T_Person (FNumber VARCHAR(20),FName VARCHAR(20),FAge INT,FWorkYear INT,CONSTRAINT ck_1 CHECK(FWorkYear< FAge))

Oracle:

CREATE TABLE T_Person (FNumber VARCHAR2(20),FName VARCHAR2(20),FAge NUMBER (10),FWorkYear NUMBER (10),CONSTRAINT ck_1 CHECK(FWorkYear< FAge))

表創建完畢後執行下面的SQL語句進行測試:


INSERT INTO T_Person(FNumber, FName, FAge, FWorkYear) VALUES("001","John",25, 30)

因為這裏將FWorkYear字段設置成了30,比如年齡25歲還大,這是違反“CHECK(FWorkYear<FAge)”這個CHECK約束的,所以在數據庫中執行此SQL語句後數據庫會報出下面錯誤信息:

  • INSERT 語句與 CHECK 約束"ck_1"沖突。該沖突發生於數據庫"demo",表"dbo.T_Person"。

而執行下面的SQL語句則可以成功執行:


INSERT INTO T_Person(FNumber, FName, FAge, FWorkYear) VALUES("001001001001001","John",25,3)

可以看到,這種定義CHECK約束的方式幾乎與定義一個復合唯一約束的方式一致。同樣,可以通過ALTER TABLE的方式為已經存在的數據表添加CHECK 約束。下面的SQL語句在T_Person上添加新的約束:


ALTER TABLE T_Person ADD CONSTRAINT ck_2 CHECK(FAge>14)

上面的SQL語句中為約束指定了顯式的名稱,所以可以通過下面的SQL語句將CHECK約束ck_2刪除(這個語句在MYSQL中無效):


ALTER TABLE T_Person

DROP CONSTRAINT ck_2;

CHECK約束