第五章 数据库完整性

一、实体完整性

1. 定义实体的完整性

关系模型的实体完整性在 CREATE TABLE 中用 PRIMARY KEY 定义。
单属性构成的码:定义为 列级 | 表级 约束条件。
多个属性构成的码,只能定义为 表级 约束条件。

    /* 单属性-列级 */
    CREATE TABLE Student
      (Sno CHAR(9) PRIMARY KEY, /* 在列级定义主码 */
      Sname CHAR(20) UNIQUE,   
      Ssex CHAR(2),
      Sage SMALLINT,
      Sdept CHAR(20)
     );    
    /* 单属性-表级 */ 
    CREATE TABLE Student
      (Sno CHAR(9),
      Sname CHAR(20) UNIQUE,   
      Ssex CHAR(2),
      Sage SMALLINT,
      Sdept CHAR(20),
      PRIMARY KEY(Sno)  /* 在表级定义主码 */
     ); 
     
     /* 属性组 */
     CREATE TABLE SC
       (Sno CHAR(9) NOT NULL,
       Cno CHAR(4) NOT NULL,
       Grade SMALLINT,
       PRIMARY KEY(Sno, Cno) /* 在表级定义主码 */
     );
2. 实体完整性检查和违约处理

用PRIMARY KEY短语定义了关系的主码后,每当用户程序对基本表插入一条记录或对主码列进行更新操作时,关系数据库管理系统将按照实体完整性规则自动进行检查。包括:
(1)检查主码值是否唯一,如果不唯一则拒绝插入或修改;
(2)检查主码的各个属性是否为空,只要有一个为空就拒绝插入或修改。
关系数据库管理系统一般都在主码上自动建立一个索引,如B+树索引,提高查找表中是否已存在主码的效率。

二、参照完整性

1. 定义参照完整性

关系模型的参照完整性在 CREATE TABLE 中用 FOREIGN KEY 短语定义哪些列为外码,用 REFERENCES 短语指明这些外码参照哪些表的主码。

    /* 建立学生选课表SC */
    CREATE TABLE SC
      (Sno CHAR(9),
      Cno CHAR(4),
      Grade SMALLINT,
      PRIMARY KEY(Sno,Cno),  /* 主码由两个属性构成,必须作为表级完整性进行定义 */
      FOREIGN KEY(Sno) REFERENCE Student(Sno),
            /* 表级完整性约束条件,Sno是外码,被参照表是Student */
      FOREIGN KEY(Cno) REFERENCE Course(Cno)
            /* 表级完整性约束条件,Cno是外码,被参照表是Course */
     );
2. 参照完整性检查和违约处理

参照完整性将两个表中的相应元组联系起来了。因此,对被参照表和参照表进行增、删、改操作时有可能破坏参照完整性,必须进行检查以保证这两个表的相容性。

被参照表(如Student) 参照表(如SC) 违约处理
可能破坏参照完整性 ← 插入元组 拒绝
可能破坏参照完整性 ← 修改外码值 拒绝
删除元组 → 可能破坏参照完整性 拒绝/级联删除/设置为空值
修改主码值 → 可能破坏参照完整性 拒绝/级联删除/设置为空值

(1)拒绝(NO ACTION)执行:一般是默认。
(2)级联(CASCADE)操作 :当删除或修改被参照表(Student)的一个元组导致与参照表(SC)不一致时,删除或修改参照表中的所有导致不一致的元组。
(3)设置为空值:如专业表中某个元组(专业号为12)被删除,学生表中专业号=12的所有元组的专业号设置为空值。

    /* 参照完整性违约处理-系统默认拒绝,也可显式说明其他处理策略 */
    CREATE TABLE SC
      (Sno CHAR(9),
      Cno CHAR(4),
      Grade SMALLINT,
      PRIMARY KEY(Sno,Cno),  /* 表级完整性定义,Sno、Cno都不能取空值 */
      FOREIGN KEY(Sno) REFERENCE Student(Sno) /* 表级完整性约束条件 */
            ON DELETE CASCADE
                            /* 当删除Student表中元组时,级联删除SC表中对应元组 */
            ON UPDATE CASCADE,
                            /* 当更新Student表中的Sno时,级联更新SC表中对应元组 */
      FOREIGN KEY(Cno) REFERENCE Course(Cno)
            ON DELETE NO ACTION
                            /* 当删除Course表中元组造成与SC表不一致时,拒绝删除 */
            ON UPDATE CASCADE
                            /* 当更新Course表中的Cno时,级联更新SC表中对应元组 */
     );

三、用户定义的完整性

1. 属性上的约束条件

在 CREATE TABLE 中定义属性同时,进行属性值限制。

  • 列值非空 ( NOT NULL )
  • 列值唯一 ( UNIQUE )
  • 检查列值是否满足一个条件表达式( CHECK短语 )
    /* Student表的Ssex只允许取"男"或"女" */
    CREATE TABLE Student
      (Sno CHAR(9) PRIMARY KEY,
      Sname CHAR(20) UNIQUE,   
      Ssex CHAR(2) CHECK(Ssex IN ('男', '女')), /* 性别属性只能是男或女 */
      Sage SMALLINT,
      Sdept CHAR(20)
     );   
    /* SC表的Grade值在0和100之间 */
    CREATE TABLE SC
      (Sno CHAR(9),
      Cno CHAR(4),
      Grade SMALLINT CHECK(Grade >= 0 AND Grade <= 100), /* Grade取值0-100 */
      PRIMARY KEY(Sno,Cno),  
      FOREIGN KEY(Sno) REFERENCE Student(Sno),
      FOREIGN KEY(Cno) REFERENCE Course(Cno)
     );    
2. 元组上的约束条件

在 CREATE TABLE 中定义元组级的限制,可以设置不同属性之间的取值的相互约束条件。

    /* 当学生性别是男时,名字不能以Ms.打头 */
    CREATE TABLE Student
      (Sno CHAR(9) PRIMARY KEY,
      Sname CHAR(20) UNIQUE,   
      Ssex CHAR(2), 
      Sage SMALLINT,
      Sdept CHAR(20),
      CHECK (Ssex = '女' OR Sname NOT LIKE 'Ms.%')
     ); /* 定义了元组中 Sname 和 Ssex 两个属性值之间的约束条件 */

四、完整性约束命名子句

1. 完整性约束命名子句

SQL 在 CREATE TABLE 中还提供了完整性约束命名子句 CONSTRAINT,用来对完整性约束条件命名,从而灵活地增加、删除一个完整性约束条件。
完整性约束条件包括:NOT NULL、UNIQUE、PRIMARY KEY、FOREIGN KEY、CHECK短语等。

    /* 完整性约束命名子句格式 */
    CONSTRAINT <完整性约束条件名><完整性约束条件>
    
    /* 建立学生登记表,要求学号在90000-99999之间,姓名非空,年龄小于30,性别取男或女 */
    CREATE TABLE Student
      (Sno NUMERIC(6)
          CONSTRAINT C1 CHECK (Sno BETWEEN 90000 AND 99999),
      Sname CHAR(20)
          CONSTRAINT C2 NOT NULL,   
      Ssex NUMERIC(3)
          CONSTRAINT C3 CHECK (Ssex IN ('男', '女')),
      Sage SMALLINT
          CONSTRAINT C4 CHECK (Sagr < 30),
          CONSTRAINT StudentKEY PRIMARY KEY (Sno)
     );
2. 修改表中的完整性限制

可以使用 ALTER TABLE 语句修改表中的完整性限制:先删除原约束条件,再增加新的约束条件。

    /* 修改年龄限制为小于40岁 */    
    ALTER TABLE Student
        DROP CONSTRAINT C4; /* 去掉年龄限制 */
    ALTER TABLE Student
        ADD CONSTRAINT C4 CHECK (Sage < 40); /* 新增年龄限制小于40 */

*五、域中的完整性限制

域是一组具有相同数据类型的集合。SQL 可以用 CREATE DOMAIN 语句建立一个域以及该域应该满足的完整性约束条件,然后就可以用域来定义属性。
这样定义的优点:数据库中不同属性来自同一个域,当域上的完整性约束条件改变时只要修改域的定义即可,不必一一修改域上的各个属性。

    /* 建立性别域,约束条件GD */
    CREATE DOMAIN GenderDomain CHAR(2)
        CONSTRAINT GD CHECK ( VALUE IN('男', '女'));
    /* 删除性别域的限制GD */
    ALTER DOMAIN GenderDomain
        DROP CONSTRAINT GD;
    /* 增加性别域的限制GDD */
    ALTER DOMAIN GenderDomain 
        ADD CONSTRAINT GDD CHECK ( VALUE IN('1', '0'));
    

六、断言

CREATE ASSERTION语句,来指定更具一般性的约束,可以定义涉及多个表或聚集操作的比较复杂的完整性约束。

1. 创建断言
    /* 创建断言的语句格式 */
    CREATE ASSERTION <断言名> <CHECK 子句>
    
    /* 限制数据库课程最多60名学生选修 */
    /* 每当学生选课时,将在SC表插入一条元组,ASSE_SC_DB_NUM断言会被触发检查,若选修
       数据库课程人数超过60人,CHECK子句返回值为假,对SC表的插入操作被拒绝 */
    CREATE ASSERTINO ASSE_SC_DB_NUM
          CHECK( 60 >= (SELECT count(*)
                 FROM Course, SC
                 WHERE Course.Cno = SC.Cno AND Course.Cname = '数据库')
                );
                
    /* 限制每个学期每门课程最多60名学生选修 */
    ALTER TABLE SC ADD TERM DATE; /* SC表新增TERM属性,类型为DATE */
    CREATE ASSERTION ASSE_SC_CNUM
        CHECK( 60 >= ALL(SELECT count(*) 
                         FROM SC 
                         GROUP by Cno,TERM));
2. 删除断言
    DROP ASSERTION <断言名>;

七、触发器

触发器又叫事件-条件-动作规则,是用户定义在关系表上的一类由事件驱动的特殊过程。任何用户对表的增、删、改操作均由服务器自动激活相应的触发器,在关系数据库管理系统核心层进行集中的完整性控制。

1. 定义触发器
    /* 一般格式 */
    CREATE TRIGGER <触发器名>  /* 每当触发事件发生时,该触发器被激活 */
    {BEFORE|AFTER} <触发事件> ON <表名> 
                                /* 指明触发器激活的时间是在执行触发事件前或后 */
    REFERENCING NEW|OLD ROW AS <变量> /* REFERENCING 指出引用的变量 */
    FOR EACH{ROW|STATEMENT}           /* 定义触发器的类型:行级|语句级,指明动作体执行频率 */
    [WHEN <触发条件>] <触发动作体> /* 仅当触发条件为真时才执行触发动作体 */
    
    
    /* 当对表SC的Grade属性修改时,若分数增加了10%,则将此次操作记录到另一个表SC_U中 */
    CREATE TRIGGER SC_T
    AFTER UPDATE OF Grade ON SC /* 触发事件为更新SC表上的Grade列*/
                                /* AFTER是触发的时机,对SC的Grade属性修改后触发下面规则*/
    REFERENCING
        OLDROW AS OldTuple,   /* 旧分数 */
        NEWROW AS NewTuple    /* 新分数 */
    FOR EACH ROW              /* 行级触发器,每执行一次Grade的更新,下面的规则就执行一次 */
    WHEN(NewTuple.Grade >= 1.1 * OldTuple.Grade)   /* 触发条件,为真才执行 */
    INSERT INTO SC_U(Sno, Cno, OldGrade, NewGrade)  /* 触发动作体,插入到新表中*/
    VALUES(OldTuple.Sno, OldTuple.Cno, OldTuple.Grade, NewTuple.Grade)
2. 激活触发器

触发器的执行是由触发事件激活,并由数据库服务器自动执行的。
同一个表上的多个触发器激活时遵循如下的执行顺序:
(1)执行该表上的BEFORE触发器;
(2)激活触发器的SQL语句;
(3)执行该表上的AFTER触发器。

3. 删除触发器
    DROP TRIGGER <触发器名> ON <表名>
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容