本文参照UESTC数据库课程整理总结而成
完整性约束
数据库完整性概述
- 完整性约束是加在数据库模式上的一个具体条件,它规定什么样的数据能够存储到数据库系统中。 例如:
学生的年龄必须是整数,取值范围为14--29;
学生的性别只能是“男”或“女”;
学生的学号一定是唯一的;
学生所在的系必须是学校开设的系;
- 数据完整性与安全性的区别
数据的完整性是为了防止数据库中存在不符合语义的数据,防止错误数据的输入和输出所造成的无效操作和错误结果。
数据的安全性是防止非法用户的非法操作所造成的对数据库的恶意破坏。
前者更重点关注用户的输入检查是否符合表的规定,后者在于防止非法用户对数据库的所有破坏操作。
完整性约束的分类
1.按照完整性越苏条件作用的对象
- 类型约束
- 属性约束
- 关系变量约束
- 数据库约束
2. 按照完整性约束时声明的位置
- 列级约束
- 表级约束
3. 两种状态:
- 静态: 对静态对象的约束是反映数据库状态合理性的约束
- 动态: 对动态对象的约束是反映数据库状态变迁的约束,新旧值之间满足的约束
完整性约束的定义
Primary Key约束(约束哪个属性是主键)
- 列级约束:
在属性定义后面直接加上主键约束
CREATE TABLE RecipeMaster{
Rno VARCHAR(10) PRIMARY KEY,
DGno VARCHAR(10),
Rdatetime DATETIME
}
- 表级约束:单属性主键
在全部属性定义完成后单独定义约束条件
CREATE TABLE Medicine{
Mno VARCHAR(10),
Mname VARCHAR(50) NOT NULL,
Mprice DECIMAL(18,2) NOT NULL,
Munit VARCHAR(10),
Mtype VARCHAR(10),
PRIMARY KEY(Mno)
}
上述为定义的单属性主键,也可以用同样的方法定义多属性组合主键。
- 表级约束:多属性组合主键
CREATE TABLE RecipeDetail{
Rno VARCHAR(10),
Mno VARCHAR(10) NOT NULL,
Mamount DECIMAL(18,0),
PRIMARY KEY(Rno,Mno)
}
UNIQUE约束
PK约束与UQ约束都要求键值不能重复。
在介绍UNIQUE约束前,先介绍下PK约束与UQ约束的不同:
- UNIQUE约束定义和PRIMARY KEY约束定义不能在同一属性上
- PRIMARY KEY要求属性取值不能为NULL,而UNIQUE允许属性取空值,允许多个空值同时存在
- 理论上PK约束是真正的主键约束
- 在一个关系中,PRIMARY KEY只有一个,而UNIQUE可以声明多个
可以说,primary key是特殊的unique key。
- 列级约束
CREATE TABLE Dept{
DeptNo VARCHAR(10) PRIMARY KEY,
DeptName VARCHAR(50) UNIQUE,
ParentDeptNo VARCHAR(10),
Manager VARCHAR(10)
}
- 表级约束
CREATE TABLE Dept{
DeptNo VARCHAR(10),
DeptName VARCHAR(50) ,
ParentDeptNo VARCHAR(10),
Manager VARCHAR(10),
PRIMARY KEY(DeptNo),
UNIQUE(DeptName )
}
在定义了UNIQUE,PRIMARY KEY 约束的属性上建立索引是十分必要的,它可以使约束的检查执行起来更有效。
- 索引对象约束
CREATE UNIQUE INDEX deptname_index ON dept(DeptName)
NOT NULL约束
一般用于列级约束
例如:
CREATE TABLE Diagnosis{
DGno VARCHAR(10) PRIMARY KEY,
Pno VARCHAR(10) NOT NULL,
Dno VARCHAR(10) NOT NULL,
Symptom VARCHAR(100),
Diagnosis VARCHAR(100),
DGtime DATETIME,
Rfee DECIMAL(18,2) NOT NULL
}
CHECK约束(在SQL Server中不支持该功能,sqlite中支持)
检查键值是否符合一些具体要求
比如性别是不是男女/年龄是不是在0-60之间
举例如下:
- 表级约束
CREATE TABLE Doctor{
Dno VARCHAR(10),
Dname VARCHAR(50) NOT NULL,
Dsex VARCHAR(2),
Dage INT,
Ddeptno VARCHAR(10),
Dlevel VARCHAR(50),
Dsalary DECIMAL(18,2),
PRIMARY KEY(Dno),
CHECK( Dsex IN (‘男’, ‘女’)),
CHECK( Dage > 0 AND Dage <60)
}
- 域对象约束
CREATE DOMAIN rfee DECIMAL(18,2)
CONSTRAINT Doctor CHECK(Dage >0)
- SQL条件约束
CREATE TABLE RecipeDetail{
Rno VARCHAR(10),
Mno VARCHAR(10) NOT NULL,
Mamount DECIMAL(18,0),
PRIMARY KEY(Rno,Mno),
CHECK (Mno IN (SELECT Mno FROM Medicine))
}
FK外键约束
格式:foreign key(字段名)references 其他表(字段名)
作用:字段的值必须是其他表中的某个对应的字段,不能随便输入。
- 列级约束
CREATE TABLE Doctor{
Dno VARCHAR(10),
Dname VARCHAR(50) NOT NULL,
Dsex VARCHAR(2),
Dage INT,
Ddeptno VARCHAR(10) REFERENCES Dept(DeptNo),
Dlevel VARCHAR(50),
Dsalary DECIMAL(18,2),
PRIMARY KEY(Dno),
CHECK( Dsex IN ('男', '女'))
}
- 表级约束
CREATE TABLE RecipeDetail{
Rno VARCHAR(10),
Mno VARCHAR(10) NOT NULL,
Mamount DECIMAL(18,0),
PRIMARY KEY(Rno,Mno),
FOREIGN KEY(Mno)REFERENCES Medicine(Mno)
}
域约束
- 通过CREATE DOMAIN可以定义一个新的域;
- 通过对域进行约束可以达到对属性列取值的约束;
- SQL92用一个特殊的关键字VALUE表示域的一个值。
- 统一约束,便于修改。
定义域:
CREATE DOMAIN SexVal CHAR(2)
CHECK (VALUE IN('男', '女'));
使用域:
CREATE TABLE Patient{
Pno VARCHAR(10),
Pname VARCHAR(50) NOT NULL,
Psex SexVal,-- 这里可以看出域的实质(属性定义+约束)
Page INT,
Pino VARCHAR(50),
Pid VARCHAR(18),
PRIMARY KEY(Pno)}
断言
格式:
CREATE ASSERTION <断言名> CHECK<谓词>
示例
Create assertion salarycheck check(
Not exists(
Select * from Doctor x
Where Dsalary >= some ( select Dsalary from Doctor y
Where x.Deptno=y.Deptno and y.Dno =(
Select Manager from Dept
Where x.Deptno =Dept.Deptno)
)
)
参照完整性的保证
我们定义RecipeDetail中FOREIGN KEY(Mno)REFERENCES Medicine(Mno),在RecipeDetail中新增、修改Mno分量,在Medicine中删除、修改Mno的分量值,则违背了完整性约束。这时应该怎么办呢?
受限策略(RESTRICTED)
- 系统默认策略
- 当出现违背参照完整性规则的更新操作请求时,系统拒绝执行该操作
置空策略(SET-NULL)
- 依照参照完整性规则,外码是可以取空值的。
- 但具体能否取空值,要根据应用环境的语义来定。
示例:
CREATE TABLE Doctor{
Dno VARCHAR(10) PRIMARY KEY,
Dname VARCHAR(50) NOT NULL,
Dsex VARCHAR(2),
Dage INT,
Ddeptno VARCHAR(10) REFERENCES Dept(DeptNo)
ON DELETE SET NULL ,
Dlevel VARCHAR(50),
Dsalary DECIMAL(18,2)
}
级联策略(CASCADE)
- 不用拒绝用户操作请求的处理方式。
- 连带处理参照数据。
示例:
CREATE TABLE RecipeDetail{
Rno VARCHAR(10),
Mno VARCHAR(10) NOT NULL,
Mamount DECIMAL(18,0),
PRIMARY KEY(Rno,Mno),
FOREIGN KEY(Mno)REFERENCES Medicine(Mno)
ON DELETE CASCADE
ON UPDATE CASCADE
}
完整性约束的修改
我们想要对约束有更多的需求,想在任何时候都可以添加、修改、删除约束。
而为了对约束进行修改、删除,有必要对约束命名。
约束命名:CONSTRAINT关键字后跟约束名称
示例:
CREATE TABLE RecipeDetail{
Rno VARCHAR(10),
Mno VARCHAR(10) CONSTRAINT notnullMno NOT NULL,
Mamount DECIMAL(18,0),
CONSTRAINT pkRecipeDetailRnoMno PRIMARY KEY(Rno,Mno),
CONSTRAINT fkRecipeDetailMnoMedicine FOREIGN KEY(Mno)REFERENCES Medicine(Mno)
ON DELETE CASCADE
ON UPDATE CASCADE
}
- 删除约束
ALTER TABLE RecipeDetail DROP CONSTRAINT pkRecipeDetailRnoMno
- 增加约束
ALTER TABLE RecipeDetail ADD CONSTRAINT pkRecipeDetailRnoMno PRIMARY KEY(Rno,Mno);
ALTER TABLE RecipeDetail ADD CONSTRAINT fkRecipeDetailMnoMedicine FOREIGN KEY(Mno)REFERENCES Medicine (Mno);
ALTER TABLE Doctor ADD CONSTRAINT checkPsex CHECK( Psex IN ('男', '女'));
ALTER DOMAIN rfee DECIMAL(18,2) DROP CONSTRAINT rfee_test;