关系数据库理论

数据依赖

数据依赖分为函数依赖(Functional Dependency,FD)和多值依赖(Multi-Valued Dependency,MVD)

规范化

函数依赖

设一个数为x,通过一定的规则f,唯一地得到一个数y,记为y=f(x),则称y对x有函数依赖。(在数学上有多值函数,即一个x对应多个y,但在计算机中函数依赖只对应一个y)

在上面的例子中,当一个学生的学号确定下来时,这个学生所处的系也就确定下来,即 S d e p t = f ( S n o ) Sdept=f(Sno) Sdept=f(Sno),那么系主任的名字也随即确定了下来,即 M n a m e = f ( S n o ) Mname=f(Sno) Mname=f(Sno)。但是当学生的学号确定下来时,他的成绩要和课程号组合才能确定,所以 G r a d e = f ( S n o , C n o ) Grade=f(Sno,Cno) Grade=f(Sno,Cno)。

函数依赖还可以这么表示x->y以为x函数确定y。

函数依赖分为几种形式:

  1. x → y x→y x→y,但 y ⊈ x y\nsubseteq x y⊈x,则 x → y x→y x→y是非平凡函数依赖。若无特别说明,所有的函数依赖均指此。
  2. x → y x\to y x→y,且 y ⊆ x y\subseteq x y⊆x,则此为平凡的函数依赖。
  3. x x x称为决定因素(determinant)
  4. 如果x决定y,且x的任何一个真子集都不能决定y,则称y对x完全函数依赖。比如说上面例子中的 S n o → S d e p t Sno\to Sdept Sno→Sdept。
  5. 除4以外,称为部分函数依赖,比如 ( 安 徽 , 上 海 ) → 中 国 (安徽,上海)\to 中国 (安徽,上海)→中国,但是仅仅只有安徽便可以决定中国,所以左边的条件对于右边来说是多余的。

如果关系中的其他属性完全依赖于一个或一组属性K,则称K为关系的码。比如SC(Sno,cno,Grade),Sno和Cno的组合决定了Grade,所以称(Sno,Cno)为关系SC的码。

至于全码和外码的概念,在基本章已经有所阐述。

第一范式(1NF)

范式,就是规则的意思,意为设计数据库是要遵循的规范。

一个数据库,最基本的规定是一个分量必须是不可分的数据项,这也就是数据库的第一范式(1NF)。我们设计一个学生管理系统,属性有学号(Sno)、系主任姓名(Mname)、系名(Sdept)三个属性,课程有课程号(Cno)、成绩(Grade)两个属性。根据1NF,可以把表设计成如下形式。

Sno Sdept Mname Cno Grade
S1 计算机系 张明 C1 95
S2 计算机系 张明 C1 90
··· ··· ··· ··· ···

但是,很明显,这个表是有问题的。

  • 数据冗余

    比如说我们要插入一个新的学生的信息,就要重复地插入系名、系主任名和课程名,这大大浪费了存储空间。

  • 更新异常(update anomalies)

    比如计算机系更换了系主任,那么就要把所有元组的Mname属性全部修改一遍。

  • 插入异常

    假如一个系刚成立,还没有学生,那么该系的系主任信息就无法存入数据库。

  • 删除异常

    假如学生全部毕业,那么系主任的信息也一并丢失。

通过上面的分析,我们可以看到,把所有属性一股脑地塞进一个表中是会出现很多问题的。那么我们便会很容易地想到,把学生的信息和系主任的信息分开保存。至于如何分开,便是下面要讨论的问题。

第二范式(2NF)

2NF规定:全部非主属性都要完全依赖于码。

我们假设有个关系货物(货物类型,货物ID,货物名称,注意事项),其中货物名称为完全依赖于主键,但是注意事项仅仅只依赖于货物类型这一个属性。这样会产生一些问题。

  • 插入异常

    假如说该公司要新增加一种新货(比如CPU芯片),但是目前没货,那么货物关系中就只有货物类型,而没有货物实体(CPU芯片并没有开始生产),也就没有货物ID,但是关键码必须给定确定的值,所以产生异常。

  • 删除异常

    假如说该公司只有一个CPU芯片,若这唯一的一个CPU芯片出售了,那么整个元组就都要删除,CPU芯片这个货物的信息也一并被删除,那么CPU芯片的注意事项就在数据库中删除了,如果客户寻求售后服务,就会出现问题。

  • 修改复杂

    当CPU的注意事项属性需要修改时,就要把表中的所有的货物类型为CPU芯片的元组全都修改。

如果仔细观察,上面问题产生的原因就是因为注意事项仅仅和货物类型有关系,但是和货物ID无关。为了解决这个问题,我们可以把这一个表拆成库存货物(货物类型,货物ID,货物名称)和货物(货物类型,注意事项)。

第三范式(3NF)

但是2NF并没有完全消除上面的问题。

假设一个关系学生管理(学号,所在系,公寓号),规定学号 → \to →所在系,所在系 → \to →公寓号学号 → \to →公寓号。由于这个表的码只有一个元素,所以一定满足2NF。

  • 插入异常

    假设学校建了一个新公寓,还没有学生入住,那么这个新公寓的信息就无法存储。

  • 删除异常

    假设一个系的学生全部毕业,那么公寓信息也一并删除。

  • 修改异常

    若要修改所在系,那么公寓号也要一并删除。

  • 数据冗余

    同一个系的学生就会有相同的公寓号,造成大量存储空间的浪费。

上面的问题主要是因为学号 → \to →所在系,所在系 → \to →公寓号,所以可以直接推出学号 → \to →公寓号,那么学号 → \to →所在系,所在系 → \to →公寓号这两个函数依赖关系就没有必要在一个表里,所以可以把它拆成两个表学-系(学号,所在系)系-公寓(所在系,公寓号)

3NF规定:在2NF基础上,任何非主属性不依赖于其它非主属性(在2NF基础上消除传递依赖)

BCNF

3NF也会产生一些问题,请看下面的例子。

  1. 如果此时在表中增加一个新书名,但是没有插入作者名字,此时主属性作者为空,根据数据表的完整性要求,主键不为空,所以此时存在插入异常。
  2. 如果书名换了作者,可能会同时修改数据表中的多个记录。
  3. 如果删除某书,此时书号和书的作者也会被删除。

BCNF规定:在3NF基础上,每一个决定因素都包含码

由于BCNF的本质其实就是消除3NF中比较隐含的函数传递关系,所以也叫扩充的3NF(不叫4NF)。

多值依赖

我们先看一种情况。假设一个仓库W只有一个保管员S,那么就有 W → S W\to S W→S,这种一对一的函数依赖上面已经说过。但是大多数实际情况是一个W会有多个S来保管,这就构成了多值依赖,表示为 W → → S W\to \to S W→→S。多值依赖有以下几种类型。

  • 平凡的多值依赖

    设总集U,X、Y、Z均为U的子集, X → → Y X\to \to Y X→→Y,且 Z = ϕ Z=\phi Z=ϕ,则X和Y为平凡的多值依赖。如上面这一种情况。

  • 非平凡的多值依赖

    如果在上面的例子中加入一个货物C属性,并规定一个W可以保存多个C,有多个S看守,那么W和S就变成了非平凡的多值依赖。

第四范式(4NF)

我们参照上面WCS关系的例子,想象仅有一个仓库,有n个保管员保管,里面存有m个货物,那么这个表的元组就有 n × m n\times m n×m个,同时仓库W大量冗余存储。

那么我们可以吧WCS关系拆分成WS和WC,这样虽然WS和WC依然是多值依赖,但已经变成了平凡的多值依赖,假设依然只有一个仓库W,前一个表的元组有n个,后一个有m个,与上面相比存储空间大大缩小。

4NF规定:限制关系模式的属性之间不允许有非平凡且非函数依赖的多值依赖

4NF的关键在于将非平凡的多值依赖中转化成平凡的多值依赖。

规范化总结

  • 1NF:每个分量必须是不可分的数据量
  • 2NF:全部非主属性都要完全依赖于码
  • 3NF:在2NF基础上,任何非主属性不依赖于其它非主属性(在2NF基础上消除传递依赖)
  • BCNF:在3NF基础上,每一个决定因素都包含码
  • 4NF:限制关系模式的属性之间不允许有非平凡且非函数依赖的多值依赖

求闭包

若属性集 X F + = A ∣ X → A 能 被 A r m s t r o n g 公 理 系 统 导 出 X_F^+={A|X\to A能被Armstrong公理系统导出} XF+​=A∣X→A能被Armstrong公理系统导出,则 X F + X_F^+ XF+​为X关于函数依赖F的闭包。

**例:**关系模式R(U,F),其中U={A,B,C,D,E,I},F={A→D,AB→E,BI→E,CD→I,E→C},计算(AE)+。

解:

第一步:令X={AE},X(0)=AE。

第二步:求X(1)。逐一扫描F集合中各个函数依赖,在F中找出左边是AE子集的函数依赖,其结果是:A→D,E→C。这是,F中这两个函数依赖要打上标记(我通常是打上√,表示已经用过,后面不能用了)。于是X(1)=AE∪DC=ACDE;

第三步:判断X(1)是否等于 X(0)以及 X(1)是否等于 U。

在这里,X(1)≠ X(0),且X(1)≠ U,所以在F中继续找出左边是ACDE子集的函数依赖,其结果是:CD→I。同样打上标记。于是X(2)=ACDE∪I=ACDEI。(这里有一个注意点,∪右边的元素只写左边没有的)

继续判断,虽然X(2)≠ X(1),但在F中未用过的函数依赖的左边属性已没有X(2)的子集,所以不必再计算下去,即(AE)+=ACDEI。

这里总结一下解题套路

**第一步:**X(0)=X。

**第二步:**求X(1)。就是在F中找,左边是X(0)的元素子集的函数依赖,打上标记√。

**第三步:**判断X(1)是否等于 X(0)以及 X(1)是否等于 U。

这里有四种情况

**第一种:**X(i)= X(i-1),说明已经找到闭包。

**第二种:**X(i)≠ X(i-1)但是X(i)= U,说明已经找到闭包。

第三种:都不相等,但是在F中未用过的函数依赖的左边属性已没有X(i)的子集,所以不必再计算下去,已经找到闭包。

第四种:都不相等,在F中未用过的函数依赖的左边属性还有X(i)的子集,重复执行。

求最小依赖集

**例:**U=(A,B,C,D,E,G) F={BG->C,BD->E,DG->C,ADG->BC,AG->B,B->D},求F最小依赖集。

解:

第一步:右边单一化。

F1={BG->C,BD->E,DG->C,ADG->B,ADG->C,AG->B,B->D}

第二步:逐个求,在去掉它的F中求闭包,如果包含右边属性,则表示这个函数依赖要去掉。

BG->C:求(BG)+=BCDEG,包含右边属性C,所以去掉。

BD->E:(BD)+=BD,不包含右边E,所以不用去掉。

DG->C:(DG)+=DG,也不用去掉。

ADG->B:(ADG)+=U,包含B,所以去掉。

ADG->C:(ADG)+包含C,去掉。(在这里,求闭包的时候,不能再用前面去掉的函数依赖了,所以如果从后往前判断,可能不用去掉ADG->B,所以最小依赖集不唯一,写出一个即可。)

AG->B:(AG)+=AG,不用去掉。

B->D:(B)+=B,不用去掉。

所以F2={BD->E,DG->C,AG->B,B->D}

第三步:对左边属性单一化,判断冗余,代替。

BD->E:B->E,求(B)+=BD,包含D,所以D冗余。

​ D->E,求(D)+=D,所以B不冗余。

​ 所以用B->E代替BD->E。

DG->C:D->C,(D)+=D,所以G不冗余。

​ G->C,(G)+=G,所以D不冗余。

AG->B:A->B,(A)+=A,所以G不冗余。

​ G->B,(G)+=G,所以A不冗余。

所以Fm={B->E,DG->C,AG->B,B->D}。

数据库设计

在数据库设计中,有“三分技术,七分管理,十二分基础数据”的说法,所以设计一个数据库,大部分都不是关于技术的,本文主要探讨关于技术的部分。

数据库设计有以下6个阶段

  • 需求分析(甲方事真多阶段)
  • 概念结构设计
  • 逻辑结构设计
  • 物理结构设计
  • 数据库实施
  • 数据库运行和维护

概念结构设计(E-R图)

E-R图是用来表示实体之间的联系。这一章没有题目很难理解,最好看书。

两个实体之间的联系

联系和实体之间存在三种关系:

  1. 一对一。比如:一个学校只能有一个校长,而一个校长也只能担任一个学校的校长。

  1. 一对多。比如:一个学校里有多名教师,而每个教师只能在一个学校教学。

  1. 多对多。比如:一个学生可以上n种课程,而每一个课程可以有m个学生学习。而上课还可以有一个属性:上课时间。

多个实体之间的联系

  1. 多个实体之间一对多。比如:一门课程可以有n个老师来授课,一个老师只讲一门课程,该门课程可以有m本参考书,而这m本书只供这一门课使用。

  1. 多个实体之间多对多。比如:一个供应商可以给多个(n)项目提供零件,每个项目可以使用多个(m)供应商供应的零件,每种§零件可有不同供应商供给。

将上面的关系组合在一起,就构成了一个完整的E-R图,多个E-R图也可以相互组合。而在组合的过程中可能会有冲突产生。最主要的是结构冲突,比如对象的属性不一样,有些对象在不同的应用中有不同的抽象,比如职工在一个应用中被当做实体,在另一个应用中被作为对象。

逻辑结构设计

E-R图转关系模型

这一章还是要看书,没有例子很难说清楚。

  • 1对1:相互吸收对方的主码作为外码,若联系有属性,则将联系作为独立的关系

  • 1对n:n端吸收1端的主码作为外码,若联系有属性,则将联系作为独立的关系

  • n对n:关系两端和关系均作为独立关系。

  • 三个或三个以上的实体的多元联系,将实体和联系均作为独立关系,其中联系关系的主键由实体的主键组成

    比如上面的例子可以转换成

    供应商(供应商名,…)

    项目(项目名,…)

    零件(零件名,…)

    供给(供应商名,项目名,零件名…)

数据库编程

随着数据库的发展,SQL语句也渐渐地向高级语言的方向融合和进化。

嵌入式SQL

嵌入式SQL就是把SQL语句和其他高级语言混合编程,SQL语句用来控制数据,其他高级语言用来控制逻辑流程。语法格式为

EXEC SQL<SQL语句>;

我感觉这一章不重要,因为现在有更好的高级语言和数据库连接交互的方案(JDBC,各种框架等等),所以只讲重要的概念。

  1. 编写主变量,使用EXEC SQL BEGIN DECLARE SECTION开始,使用``EXEC SQL BEGIN DECLARE SECTION结束。需要注意的是在SQL语句中主变量前面需要加冒号:`以示区分。

  2. 定义SQL通信区,使用EXEC SQL INCLUDE SQLCODE。通信区中有一个变量SQLCODE,这个变量被赋予每次执行SQL语句后返回的代码,程序员用来根据代码查找错误。该变量要在定义通信区之前设定。

  3. 建立和关闭数据库连接,使用EXEC SQL CONNECT TO XXX@DB,用来连接本地或云端上的数据库。使用EXEC SQL DISCONNECT XXX关闭连接。

  4. 定义游标(cursor)。游标是一个数据缓存区,因为大多数高级语言的变量只能存储一个数据,而SQL语句返回的常常是个集合,所以使用游标。使用

    EXEC SQL DECLARE SX CORSOR FOR
    SX对应的语句
    

    来设置游标。使用EXEC SQL OPEN SX;打开游标。使用EXEC SQL FECTH SX INTO :XXX,:AAA;推进游标。使用EXEC SQL CLOSE SX;关闭游标。

  5. 在更改结束之后,还要EXEC SQL COMMIT WORK;提交更新。

过程化SQL

过程化SQL允许用户在SQL语句中设置变量和常量,写循环语句和条件控制语句。很少用。略。

存储过程

  • 定义

是一组预编译的sql语句,也就是给pl/sql语句包装起来,完成一次创建任意调用的功能,相当于java中的方法。经编译之后存储在数据库中,用户通过制定存储过程的名字并给出参数(如果该存储过程带有参数的话)来执行它。

  • 语法
create [or replace] procedure 存储过程名(参数名1 in/out 参数类型1,参数名2 in/out 参数类型2)is/as——声明部分begin——业务逻辑部分end;

举个栗子:给指定员工涨薪,并打印涨薪前和涨薪后的工资。

    create or replace procedure proc_updatesal(vempno in number,vnum in number)is--声明变量.记录当前工资vsal number;begin--查询当前的工资select sal into vsal from emp where empno = vempno;--输出涨薪前的工资dbms_output.put_line('涨薪前:'||vsal);--更新工资update emp set sal = vsal + vnum where empno = vempno;--输出涨薪后的工资dbms_output.put_line('涨薪后:'||(vsal+vnum));--提交commit;end;

存储函数

  • 定义

通常存储函数是给存储过程调用的。

  • 语法
create [or replace] function存储函数名(参数名1 in/out 参数类型1,参数名2 in/out 参数类型2) return 返回类型is/as——声明部分(声明结果变量)begin——业务逻辑部分return (结果变量);end;

举个栗子:查询指定员工的年薪。

    create or replace function func_getsal(vempno number) return numberis--声明变量.保存年薪vtotalsal number;beginselect sal*12 + nvl(comm,0) into vtotalsal from emp where empno = vempno;return vtotalsal;end;

存储过程和存储函数的区别

  1. 存储函数可以有返回值也可以没有返回值,存储函数不许有返回值

  2. 存储过程和存储函数都可以通过输出参数out实现多个返回值

怎么选择?

原则上只有一个返回值用存储函数,否则用存储过程

但是我们一般都是用存储过程,因为

  1. 存储过程可以有返回值也可以没有返回值,存储的灵活性

  2. 存储过程既然有返回值了,可以替代存储函数

  3. oracle新版中已经不推荐使用存储函数了


参考文献

https://blog.csdn.net/weixin_43971764/article/details/88677688

https://baike.baidu.com/item/第二范式/3193760?fr=aladdin

https://blog.csdn.net/fjxcsdn/article/details/105310435

https://wonzwang.blog.csdn.net/article/details/80464466

https://blog.csdn.net/chenpidaxia/article/details/62073162

https://www.cnblogs.com/sun7897/p/8592931.html

数据库(设计与应用)相关推荐

  1. MySQL 学习笔记(14)— 数据库设计流程、实体关系图、第一范式、第二范式、第三范式、外键使用

    本文参考:https://gitbook.cn/gitchat/column/undefined/topic/5db92c12a9c3a53bc3800f0c 1. 数据库设计流程 数据库设计是对数据 ...

  2. 软件设计之 数据库设计

    [按语:在软件设计或是动态网站开发中,数据库设计时很重要,我觉得可以说是开发工作的核心部分,所以学好数据库设计,是很重要的,也是大有前途的...]  ◆.概念 首先要搞清楚容易混淆的两个概念:&quo ...

  3. 一套外企的数据库设计面试题

    最近发现园子里面关于数据库方面的文章比较多,正好我也是一个喜欢凑热闹的家伙,那就跟着烧一把火吧.^_^ 这是前阵子一个朋友面试外企的一套关于数据库设计的试题,有兴趣的朋友不妨一试. Part I   ...

  4. saas的计费数据库设计_如何构建和扩展SaaS计费解决方案

    saas的计费数据库设计 您需要的最低可行产品 (What you need for a Minimum Viable Product) When you are building your Soft ...

  5. 互联网产品mysql数据库设计总结

    mysql数据库性能不比oracle数据库,所以设计上,和oracle有一些不同.下面总结一些互联网产品的数据库设计. 1.主键 主键可以使用bigint(20) unsigned也可以使用varch ...

  6. 数据库设计 之设计 表字段类型

    2019独角兽企业重金招聘Python工程师标准>>> 数据库设计 之设计 表字段类型 博客分类: sql 之前没有 数据库设计的一些经验. 这次数据库设计.由于需求原因和没经验原因 ...

  7. 一、数据库设计与性能优化--概述

    前言 我1998年第一次接触SQL Server 6.5 for Windows NT 4.0,当时的感觉就认为SQL Server只是一个功能强大的Excel文件.现在回想起来,当年抱着这样一种态度 ...

  8. 数据库设计的10个最佳实践

    作者 | Emily Williamson 译者 | 孙薇,责编 | 屠敏 出品 | CSDN(ID:CSDNnews) 以下为译文: 数据库是应用及计算机的核心元素,负责存储运行软件应用所需的一切重 ...

  9. 关系型数据库设计要领(值得收藏)

    欢迎关注方志朋的博客,回复"666"获面试宝典 摘要 本文讨论关系数据库设计相关的一些内容,涉及关系模型,表结构设计等内容,以学生选修课程讲述设计过程,在尽量讲清楚设计要领的前提下 ...

  10. 数据库设计三大范式和ER模型

    1. 数据库设计之三范式的介绍 范式: 对设计数据库提出的一些规范,目前有迹可寻的共有8种范式,一般遵守3范式即可. 第一范式(1NF): 强调的是列的原子性,即列不能够再分成其他几列.(1NF强调字 ...

最新文章

  1. 关于JAVA中log4j与logslf4j打印日志用法
  2. JingRiverOS的自由软件之路
  3. cmd运行Java中文乱码,无法加载主类Error: Could not find or load main class
  4. secondarynamenode异常
  5. “并发用户数”、“系统用户数”和“同时在线用户数”的计算公式
  6. 【最优解法】1087 有多少不同的值 (20分)_17行代码AC
  7. 2018/03/25
  8. 如何在Windows Defender中安排扫描
  9. 【剑指offer】_14 不用加减乘除做加法
  10. python try语句相关(try/except/else/finally)
  11. 设计模式笔记一:工厂模式
  12. 车场系统服务器内存莫名急速下降,宝德工控机在停车场监控系统的解决方案
  13. firefox启动很慢 linux_Firefox启动太慢怎么办
  14. 浅谈mysql主从复制的高可用解决方案
  15. 窗口变化相关消息 OnSize、OnSizing和OnGetMinMaxInfo
  16. 前端html5 css3 教案,Web前端开发任务驱动式教程(HTML5+CSS3+JavaScript)
  17. Android Studio连接MySQL:问题解决:虚拟机无法连接本地SQL,coon总为空
  18. MitraStar DSL-2401HN-T1C-GV硬件与启动信息
  19. Zend框架:Zend_Nosql_Mong​​o组件建议
  20. laravel——实现Email形式的邮箱验证注册以及登陆功能

热门文章

  1. Python:企业微信接口封装库work-weixin-api
  2. python 自动化测试基础
  3. 扫盲贴 家用无线路由的安全设置
  4. 拓扑数据分析在机器学习中的应用
  5. 文件下载中文文件名乱码问题解决
  6. Python实现烟花效果,祝大家2021年,牛年大吉。
  7. 查找list中重复数据
  8. final修饰的变量
  9. css高度根据宽度自适应显示,按比例显示宽高
  10. 让人扎心的Nginx rewrite跳转及Location