Post

完整性

完整性

整个数据库完整性的知识体系,可以看作是解决一个核心问题:如何确保数据库里的数据是正确的、符合逻辑的? 为了解决这个问题,数据库系统提供了一套由简到繁、由内到外的“防御系统”。

一、数据库完整性概述

1.1 什么是数据库完整性?

  • 数据的正确性:数据符合现实世界语义,反映实际状况。
  • 数据的相容性:同一对象在不同表中的数据逻辑一致。

1.2 完整性 vs 安全性

截屏2025-10-20 14.03.43

1.3 完整性机制

  1. 定义完整性约束
    • 使用 SQL 的 DDL 语句定义
    • 包括:实体完整性、参照完整性、用户定义完整性
  2. 完整性检查
    • 在执行 INSERTUPDATEDELETE 后或事务提交时检查
  3. 违约处理
    • 拒绝执行(NO ACTION)
    • 级联操作(CASCADE)
    • 设置为空值(SET-NULL)

二、实体完整性

2.1 定义

  • 使用 PRIMARY KEY 定义主码
  • 主码唯一且非空

2.2 定义方式

  • 列级定义
    1
    2
    3
    4
    
    CREATE TABLE Student (
      Sno CHAR(8) PRIMARY KEY,
      ...
    );
    
  • 表级定义(适用于多属性主码):
    1
    2
    3
    4
    5
    
    CREATE TABLE SC (
      Sno CHAR(8),
      Cno CHAR(5),
      PRIMARY KEY (Sno, Cno)
    );
    

2.3 检查与违约处理

  • 检查主码是否唯一、非空
  • 使用 B+ 树索引避免全表扫描
  • 违约则拒绝操作

三、参照完整性

3.1 定义

  • 使用 FOREIGN KEYREFERENCES 定义外码
  • 外码引用其他表的主码

3.2 示例

1
2
3
4
5
6
CREATE TABLE SC (
  Sno CHAR(8),
  Cno CHAR(5),
  FOREIGN KEY (Sno) REFERENCES Student(Sno),
  FOREIGN KEY (Cno) REFERENCES Course(Cno)
);

3.3 违约处理

| 操作 | 说明 | | ——— | —————- | | NO ACTION | 拒绝执行(默认) | | CASCADE | 级联删除/更新 | | SET-NULL | 将外码设为空值 |

3.4 显式定义违约处理

1
2
3
FOREIGN KEY (Sno) REFERENCES Student(Sno)
  ON DELETE CASCADE
  ON UPDATE CASCADE;

四、用户定义完整性

4.1 属性级约束

  • 非空NOT NULL
  • 唯一UNIQUE
  • 条件检查CHECK

示例:

1
2
3
4
5
6
CREATE TABLE Student (
  Sno CHAR(8) PRIMARY KEY,
  Sname CHAR(20) NOT NULL,
  Ssex CHAR(6) CHECK (Ssex IN ('男', '女')),
  Grade SMALLINT CHECK (Grade BETWEEN 0 AND 100)
);

4.2 元组级约束

  • 可定义多个属性间的逻辑关系

示例:

1
2
3
4
CREATE TABLE Student (
  ...
  CHECK (Ssex = '女' OR Sname NOT LIKE 'Ms.%')
);

4.3 完整性约束命名与修改

  • 使用 CONSTRAINT 命名
  • 使用 ALTER TABLE 修改

示例:

1
2
3
4
5
6
-- 添加约束
ALTER TABLE Student
ADD CONSTRAINT C1 CHECK (Sno BETWEEN '900000' AND '999999');

-- 删除约束
ALTER TABLE Student DROP CONSTRAINT C1;

五、域与断言

5.1 域(Domain)

  • 定义一组具有相同数据类型和约束的值集合

示例:

1
2
3
4
5
CREATE DOMAIN GenderDomain CHAR(6)
CHECK (VALUE IN ('男', '女'));

-- 使用域
Ssex GenderDomain

5.2 断言(Assertion)

  • 定义跨表的复杂约束
  • 任何相关操作都会触发检查

示例:

1
2
3
4
5
6
-- 限制“数据库”课程最多60人选修
CREATE ASSERTION ASSE_SC_DB_NUM
CHECK (60 >= (
  SELECT COUNT(*) FROM SC, Course
  WHERE SC.Cno = Course.Cno AND Course.Cname = '数据库'
));

六、触发器

6.1 触发器概述

  • 是一种“事件-条件-动作”规则
  • INSERTUPDATEDELETE 激活
  • 可在操作前(BEFORE)或后(AFTER)执行

6.2 触发器类型

  • 行级触发器:每行触发一次,可使用 NEW/OLD
  • 语句级触发器:每语句触发一次,不能使用 NEW/OLD

6.3 示例

例1:记录分数修改

1
2
3
4
5
6
7
8
CREATE TRIGGER SC_T
AFTER UPDATE OF Grade ON SC
REFERENCING
  OLD AS OldTuple,
  NEW AS NewTuple
FOR EACH ROW
WHEN (NewTuple.Grade >= 1.1 * OldTuple.Grade)
INSERT INTO SC_U VALUES (OldTuple.Sno, OldTuple.Cno, OldTuple.Grade, NewTuple.Grade);

例2:统计插入学生数

1
2
3
4
5
CREATE TRIGGER Student_Count
AFTER INSERT ON Student
REFERENCING NEW TABLE AS Delta
FOR EACH STATEMENT
INSERT INTO StudentInsertLog SELECT COUNT(*) FROM Delta;

例3:自动调整教授工资

1
2
3
4
5
6
7
8
9
CREATE TRIGGER Update_Sal
BEFORE UPDATE ON Teacher
REFERENCING NEW AS newTuple
FOR EACH ROW
BEGIN
  IF newTuple.Job = '教授' AND newTuple.Sal < 4000 THEN
    SET newTuple.Sal = 4000;
  END IF;
END;

6.4 触发器执行顺序

  1. 执行 BEFORE 触发器
  2. 执行触发 SQL 语句
  3. 执行 AFTER 触发器

6.5 删除触发器

1
DROP TRIGGER Update_Sal ON Teacher;

总结回顾

模块核心机制关键字/语句
实体完整性主码唯一非空PRIMARY KEY
参照完整性外码引用FOREIGN KEYREFERENCES
用户定义完整性属性/元组级约束CHECKNOT NULLUNIQUE
域与断言类型约束、跨表约束CREATE DOMAINCREATE ASSERTION
触发器事件驱动、复杂逻辑CREATE TRIGGERNEW/OLD
This post is licensed under CC BY 4.0 by the author.

Trending Tags