当前位置: 首页 > news >正文

数据库完整性

一、核心概念

(一)数据库完整性定义
  • 目标:确保数据的正确性(符合语义约束)和相容性(数据间逻辑一致),防止无效数据输入输出(如 “垃圾进垃圾出” 问题)。
  • 与安全性区别:
    • 完整性:关注数据本身的语义合法性,防止错误数据。
    • 安全性:关注数据的访问控制,防止恶意破坏和非法存取。
(二)完整性约束条件
  • 作用对象:列(属性)、元组(记录)、关系(表)。

  • 分类:

    类型对象说明
    静态列级约束限制列的取值范围(如数据类型、格式、值域、非空等)。
    静态元组约束元组元组内各列之间的逻辑关系(如年龄 > 0 且工资 > 年龄 ×100)。
    静态关系约束关系表间或表内元组的关联约束(如实体完整性、参照完整性、函数依赖)。
    动态列级约束修改列定义或值时的约束(如修改列类型时需保证数据兼容)。
    动态元组约束元组元组值修改前后的逻辑关系(如工资调整后不能低于原工资的 90%)。
    动态关系约束关系表状态变化的约束(如事务的原子性、一致性)。

二、完整性控制机制

(一)DBMS 的核心功能
  1. 定义功能:通过 DDL 语句(如CREATE TABLE)声明完整性约束。
  2. 检查功能:在数据插入、更新、删除时触发约束检查。
  3. 处理功能:若违反约束,执行预设动作(如拒绝操作、级联更新、自动修复数据)。
(二)约束检查方式
  • 立即执行约束:操作完成后立即检查(默认方式)。
  • 延迟执行约束:事务提交前检查(适用于跨表或跨事务的约束)。
(三)完整性规则模型
  • 五元组表示

    (D, O, A, C, P)
    
    • D:约束作用的数据对象(如列、表)。
    • O:触发约束的操作(如INSERTUPDATE)。
    • A:约束条件(如 “工资≥1000”)。
    • C:筛选数据的谓词(如 “职称 =‘教授’”)。
    • P:违反约束时的处理过程(如拒绝操作、设置默认值)。

示例

  • 约束

    :教授工资不得低于 1000 元。

    • D:工资列(Sal)
    • OUPDATE操作
    • A:Sal ≥ 1000
    • C:职称 =‘教授’
    • P:拒绝执行更新

三、典型完整性约束实现

(一)实体完整性
  • 目标:确保表中每一行数据唯一标识(通过主码实现)。

  • SQL 实现

    (Oracle 示例):

    CREATE TABLE Student (Sno NUMBER(8) CONSTRAINT PK_SNO PRIMARY KEY, -- 单字段主码Sname VARCHAR(20),Sage NUMBER(20)
    );CREATE TABLE SC (Sno NUMBER(8),Cno NUMBER(2),Grade NUMBER(2),CONSTRAINT PK_SC PRIMARY KEY(Sno, Cno) -- 联合主码
    );
    
(二)参照完整性
  • 目标:维护表间关联数据的一致性(通过外码实现)。

  • 关键问题:

    • 外码是否允许为空值?
    • 被参照表删除 / 更新主码时的级联操作(如CASCADERESTRICTSET NULL)。
  • SQL 实现

    (Oracle 示例):

    CREATE TABLE EMP (Empno NUMBER(4),Deptno NUMBER(2),CONSTRAINT FK_DEPTNO FOREIGN KEY(Deptno)REFERENCES DEPT(Deptno) ON DELETE CASCADE -- 级联删除
    );
    
(三)用户定义完整性
  • 目标:自定义业务规则(如值域、格式、逻辑运算约束)。

  • SQL 实现:

    1. 非空约束(NOT NULL):

      CREATE TABLE Student (Sname VARCHAR(20) CONSTRAINT C2 NOT NULL -- 姓名非空
      );
      
    2. 唯一约束(UNIQUE):

      CREATE TABLE DEPT (Dname VARCHAR(9) CONSTRAINT U1 UNIQUE -- 部门名称唯一
      );
      
    3. 检查约束(CHECK):

      CREATE TABLE Student (Sno NUMBER(5) CONSTRAINT C1 CHECK(Sno BETWEEN 90000 AND 99999), -- 学号范围Ssex VARCHAR(2) CONSTRAINT C4 CHECK(Ssex IN('男','女')) -- 性别枚举
      );
      
    4. 基于表达式的约束:

      CREATE TABLE EMP (Sal NUMBER(7,2),Deduct NUMBER(7,2),CONSTRAINT C1 CHECK(Sal + Deduct <= 3000) -- 应发工资上限
      );
      

四、高级实现:触发器(Trigger)

  • 作用:对复杂业务规则(如跨表约束、自动数据修复)进行编程控制。

  • 示例

    :教授工资低于 4000 元时自动调整为 4000 元(Oracle PL/SQL):

    CREATE TRIGGER UPDATE_SAL
    BEFORE INSERT OR UPDATE OF Sal, Pos ON Teacher
    FOR EACH ROW
    WHEN (NEW.Pos = '教授')
    BEGINIF NEW.Sal < 4000 THENNEW.Sal := 4000; -- 自动修复数据END IF;
    END;
    

五、总结

  • 核心原则:通过多层约束(列级、元组级、关系级)和动态机制(触发器)确保数据符合业务语义。
  • 实践建议:
    • 优先使用 DBMS 内置约束(如PRIMARY KEYCHECK)实现简单规则。
    • 复杂规则通过触发器或应用层逻辑实现,避免过度依赖数据库层。
    • 结合事务机制(如COMMIT/ROLLBACK)处理延迟约束,保证数据一致性。

第八章 关系数据理论

一、核心理论与问题引入

(一)关系模式与数据依赖
  • 关系模式定义
    形式化表示为 R(U, F),其中 U 是属性集合,F 是函数依赖集合。例如,学生选课关系 SC(Sno, Cno, Grade) 中,F = {(Sno, Cno)→Grade}
  • 数据依赖类型:
    • 函数依赖(FD):如 Sno→Sdept(学号决定所在系)。
    • 多值依赖(MVD):后续章节深入,本章以函数依赖为主。
(二)不良模式的四大问题(以学生 - 系 - 课程表为例)
问题类型具体表现
数据冗余系主任姓名重复存储(如计算机系的 “张明” 重复出现在所有该系学生记录中)。
更新异常修改系主任时需更新所有该系学生记录,漏改会导致数据不一致。
插入异常新系无学生时无法插入系信息(主码 (Sno, Cno) 不能为空)。
删除异常删除最后一个学生记录时,系信息也被删除(“级联删除” 副作用)。

解决思路:通过模式分解将一个 “大而全” 的关系拆分为多个 “小而精” 的关系,如拆分为 Student(Sno, Sdept)Dept(Sdept, Mname)SC(Sno, Cno, Grade)

二、核心概念:码与函数依赖

(一)码的分类与判定
  1. 候选码:

    • 唯一标识元组最小化的属性组,如 SC(Sno, Cno) 中的 (Sno, Cno)
  2. 判定原则:

    1. 出现在所有函数依赖左部的属性必为主属性(如 SnoSno→Sdept 左部,是主属性)。
    2. 不在任何函数依赖中的属性必包含在候选码中(全码场景,如 R(P, W, A) 中无函数依赖,全属性组为码)。
    3. U中只出现在F中函数依赖的右部的属性,一定不是主属性,不出现在任何码中。
  3. 主码:从候选码中选定的一个,如学生表选 Sno 为主码。

  4. 外码:其他表的主码,如 SC 中的 SnoStudent 表的主码,故为外码。

(二)函数依赖的类型
  1. 完全函数依赖:

    • 记为 X →^F Y,如 (Sno, Cno)→Grade(单个 SnoCno 无法决定 Grade)。
  2. 部分函数依赖

    • 记为 X →^P Y,如 (Sno, Cno)→Sdept(仅 Sno 即可决定 Sdept)。
  3. 传递函数依赖

    • Sno→Sdept→Mname,则 Sno→^t Mname 是传递依赖(Sdept 是中间属性)。

例题:

考虑某商业集团数据库中的关系模式:销售(商店编号,商品编号,库存数量,部门编号,负责人)。若规定:①每个商店的每种商品只在一个部门销售;②每个商店的每个部门只有一个负责人;③每个商店的每种商品只有一个库存数量。

解析:

•根据语义,此关系模式满足的函数依赖为:

① (商店编号,商品编号)→部门编号

② (商店编号,部门编号)→负责人

③ (商店编号,商品编号)→库存数量

•由于商店编号和商品编号只出现在函数依赖的左部,码中必含有这两个属性。且(商店编号,商品编号)能够完全函数决定该关系的所有属性,因此候选码(也是主码)为:(商店编号,商品编号)。

•主属性包括:商店编号和商品编号。

非主属性包括:部门编号、负责人和库存数量。

三、范式分解:从 1NF 到 BCNF

(一)范式层级与判定标准
范式核心要求解决的问题
1NF属性不可再分(如 “地址” 不能包含省、市、区多列)。基础格式规范
2NF消除非主属性对码的部分依赖(如拆 S-L-C(Sno, Cno, Sdept, Sloc, Grade)SCS-L)。部分依赖导致的冗余
3NF消除非主属性对码的传递依赖(如拆 S-L(Sno, Sdept, Sloc)S-DD-L)。传递依赖导致的冗余
BCNF消除主属性对码的不良依赖(如 STJ(S, T, J)T→J 需拆分为 STTJ)。主属性间的依赖异常

(二)分解步骤与示例
1. 从非 2NF 到 2NF:消除部分依赖

案例:关系模式 S-L-C(Sno, Cno, Sdept, Sloc, Grade)

  • 函数依赖
    (Sno, Cno)→^F GradeSno→^P SdeptSno→^P SlocSdept→Sloc)。

  • 分解步骤:

    • 保留完全依赖:SC(Sno, Cno, Grade)
    • 提取部分依赖:S-L(Sno, Sdept, Sloc)
  • 结果SC∈2NFS-L∈2NF(但 S-L 仍存在传递依赖,需进一步分解)。

2. 从 2NF 到 3NF:消除传递依赖

案例:关系模式 S-L(Sno, Sdept, Sloc)

  • 函数依赖Sno→Sdept→SlocSno→Sloc 是传递依赖)。
  • 分解步骤:
    • 保留直接依赖:S-D(Sno, Sdept)
    • 提取传递依赖:D-L(Sdept, Sloc)
  • 结果S-D∈3NFD-L∈3NF
3. 从 3NF 到 BCNF:消除主属性依赖

案例:关系模式 STJ(S, T, J)(学生 - 教师 - 课程,T→J

  • 函数依赖(S, J)→T(S, T)→JT→JT 是决定因素但非码)。
  • 分解步骤:
    • 提取 T→JTJ(T, J)
    • 保留剩余属性:ST(S, T)
  • 结果TJ∈BCNFST∈BCNF(所有决定因素均包含码)。

四、寻找码的实用技巧

(一)属性分类法
  1. L 类属性:只出现在函数依赖左部(如 SnoOrderNo),必为主属性,包含在候选码中。
  2. R 类属性:只出现在函数依赖右部(如 GradeSloc),必为非主属性,不包含在候选码中。
  3. N 类属性:未出现在任何函数依赖中,必包含在候选码中(全码场景)。
  4. LR 类属性:同时出现在左、右部(如 SdeptT),需进一步判断。
(二)闭包计算法(简化版)
  1. 步骤:
    • 假设候选码为 X,从 L 类和 N 类属性开始,逐步添加 LR 类属性。
    • 计算 X 的闭包 X+,若 X+ = U,则 X 是候选码。
  2. 示例:
    • 关系模式 销售(商店编号, 商品编号, 库存数量, 部门编号, 负责人)
    • L 类:商店编号, 商品编号;R 类:库存数量, 部门编号, 负责人
    • 计算 (商店编号, 商品编号)+:通过函数依赖推导,可决定所有属性,故为候选码。

五、规范化实战:书店订单案例

题目:

考虑某书店的图书销售关系Book_Order,该关系涉及的属性包括:OrderNo(订单号)、ClientNo(客户号)、ClientName(客户名)、Address(客户地址)、BookNo(书号)、Title(书名)、Publisher(出版社)、Price(单价)、Quantity(订购数量)。

根据现实世界已知的事实,对于上述关系有如下语义:

•订单号、客户号和书号分别是订单、客户和图书的标识。

•每份订单只对应唯一的一个客户,但一个客户可以有多个订单。

•每个客户有唯一的客户名称和地址。

•每种图书有唯一的书名、出版社和单价。

•每份订单可以包含多种图书,每种图书可以在多份订单中订购。

•每份订单订购每一种图书,有唯一的订购数量。

(一)原始关系:Book_Order
  • 属性OrderNo, ClientNo, ClientName, Address, BookNo, Title, Publisher, Price, Quantity

  • 函数依赖
    OrderNo→ClientNo

    ClientNo→ClientName, Address

    BookNo→Title, Publisher, Price

    (OrderNo, BookNo)→Quantity

  • 主码:(orderNo,BookNo)

  • 问题:非主属性 ClientName, Address, Title 等存在部分依赖和传递依赖。

(二)分解过程
  1. 第一步:拆分为 3 个关系(消除部分依赖)
    • OrderClient(OrderNo, ClientNo)(主码 OrderNo
    • Client(ClientNo, ClientName, Address)(主码 ClientNo
    • OrderBook(OrderNo, BookNo, Quantity)(主码 (OrderNo, BookNo)
    • Book(BookNo, Title, Publisher, Price)(主码 BookNo
  2. 验证:
    • 所有非主属性完全依赖于码,且无传递依赖,满足 3NF。
    • 若需进一步优化(如 BookPublisher 是否需要独立成表),可根据业务需求决定是否拆至 BCNF。

六、核心总结:范式选择与平衡

  • 优先目标
    一般业务系统分解至 3NF 即可,避免过度分解导致多表连接性能下降。

  • 判断口诀

    • 1NF:属性原子化,拒绝 “表中表”。
    • 2NF:码是组合键时,检查非主属性是否部分依赖。
    • 3NF:非主属性间不能 “间接决定”(如 A→B→C 需拆)。
    • BCNF:主属性也不能 “任性决定”(如 教师→课程 需拆)。
  • 终极目标
    消除冗余与异常,同时兼顾查询效率,通过索引优化关联查询(如为外码添加索引)

相关文章:

  • 【吾爱】逆向实战crackme160破解记录(二)
  • 从“remote rejected”看git角色区别,Maintainer和Devoloper
  • GaLore:基于梯度低秩投影的大语言模型高效训练方法详解一
  • 开发体育比分平台,有哪些坑需要注意的
  • 深入对比主流Java Web服务器与框架
  • 前端​​HTML contenteditable 属性使用指南
  • 黑马Java面试笔记之 消息中间件篇(RabbitMQ)
  • 【办公类-48-04】202506每月电子屏台账汇总成docx-5(问卷星下载5月范围内容,自动获取excel文件名,并转移处理)
  • MybatisPlus--核心功能--service接口
  • PHP+mysql 美容美发预约小程序源码 支持DIY装修+完整图文搭建教程
  • 对 `llamafactory-cli api -h` 输出的详细解读
  • 【python与生活】用 Python 从视频中提取音轨:一个实用脚本的开发与应用
  • 【前端后端环境】
  • 燃尽图和甘特图
  • 【结构型模式】装饰器模式
  • 如何轻松地将数据从 iPhone传输到iPhone 16
  • godwork_ AT 5.2 摄影测量空三数据处理软件。
  • Monorepo 详解:现代前端工程的架构革命
  • OpenCV CUDA模块霍夫变换------在 GPU 上执行概率霍夫变换检测图像中的线段端点类cv::cuda::HoughSegmentDetector
  • Selenium 中 JavaScript 点击的优势及使用场景
  • 专题网站建设意义何在/沈阳seo代理计费
  • 做网站如何处理并发问题/长春关键词优化公司
  • 甘肃做网站的公司/流量平台
  • 天猫店铺装修做特效的网站/自己如何制作一个网站
  • 专业的徐州网站开发/百度广告代理商加盟
  • 长沙百度网站建设/广告推销网站