Ch5. Embedded SQL (嵌入式SQL)
1. 定义
嵌入式SQL是将SQL嵌入到某一种高级语言之中,如C/C++,Java等 这种高级语言被称为宿主语言
2. 特性
1)继承了高级语言的过程控制性
2) 结合了SQL语言的复杂结果集操作的非过程性
3) 为数据库操作者提供了安全可靠的操作方式:通过应用程序进行操作
3. 和交互式SQL的对比
1) 交互式(Interactive SQL ):
1 | select Sname,Sage from Students where Sname = "张三"; |
2) 嵌入式(Embedded SQL, 此文宿主语言为C):
1 | exec sql select Sname,Sage into :vSname,:vSage from Students where Sname = "张三"; |
1. exec sql : 引导SQL语句,提供给C编译器,以便对SQl语句预编译成C编译器可识别的语句
2. into 子句: 用于把SQL 语句的检索结果赋给高级语言的程序变量
3. 用冒号开头:
- 表示高级语言的程序变量 :vsname , :vsage
- 冒号很重要, 用于区分是程序变量还是表的字段!!
4. 宿主语言如何与数据库连接
连接:
1 | exec sql connect to target-server as connect-name user user-name; |
断开:
1 | exec sql disconnect connect-name; |
5. 如何将宿主语言的变量传递给SQL语句
变量声明:
1 | exec sql begin declare section; |
变量使用:
- 变量可传递给SQL语句的where等字句,以便SQL语言能够按照指定的要求进行检索
1 | exec sql select Sname,Sage into |
6. SQL语句如何执行
1) SQL语句在执行过程中,必须有提交和撤销语句才能确认其操作结果
提交:
1 | exec sql commit work |
撤销:
1 | exec sql rollback work |
7. 事务
1) 定义:
- 事务是一个存取或改变数据库内容的程序的一次执行,或者说一条或多条SQL语句的一次执行被看做一个事务,一般由应用程序提出,有开始和结束,结束前需要提交或撤销
2) 事务的ACID 特性
- 原子性Atoomicity:DBMS能够保证事务的一组更新操作是原子不可分的,要么全做,要么全不做
- 一致性Consistency: DBMS保证事务的操作状态是正确的
- 隔离性Isolation: DBMS保证并发的多个事务之间相互不受影响
- 持久性Durability:DBMS保证已提交事务的影响是持久的,被撤销事务的影响是可恢复的
8. 如何将SQL检索到的结构传递回宿主程序进行处理
1) 单行结果处理
检索单行结果,可以将结果直接传到宿主程序的变量中
1
2
3
4exec sql select [ALL|DISTINCT] expression [,expression...]
INTO host-variable,[host-variable,...]
From tableref [corr_name][,tableref[corr_name]...]
Where search_condition;Eg:
1
exec sql select Sname,Sage into :vSname,:vSage from Student where Sname=:specName;
2) 多行结果处理
游标(Cursor)
1. 游标是指向某检索记录集的指针,通过这个指针的移动,每次读一行,处理一行,再读一行,直到处理完毕 ;
2. 读一行的操作是通过Fetch…into实现的,每一次Fetch,都是先向下移动指针,然后再读取,记录集有结束表示EOF,用来标记后面已经没有记录了 ;
3. 游标的使用需要先定义,再打开,接着一条一条处理,最后关闭 。
Cursor的定义:
1
2
3
4EXEC SQL DECLARE cursor_name CURSOR FOR
Subquery
[ORDER BY result_column [ASC|DESC][,result_column...]]
[FOR [READ ONLY |UPDATE [OF columnname[,columnname....]]]]Eg:
1
2
3
4
5exec sql declare cur_student cursor for
select Sno ,Sname,Sclass from Student where Sclass=:vClass
order by Sno
--只读属性
for read only;
Cursor的打开和关闭
打开:
1
exec sql open cursor_name;
关闭:
1
exec sql close cursor_name;
Cursor的数据读取(多行,并传入宿主程序变量)
1
2exec sql fetch cursor_name
into host-variable,[host-variable,...]Eg:
1
exec sql fetch cur_student into :vSno,:vSname,:vSage;
9. 数据库的删除与更新
1) 删除
查找删除:
1
exec sql delete from tablename [corr_name] where search_condition
Eg:
1
exec sql delete from customers c where c.city='Harbin' and not exists (select * from orders o where o.cid=c.cid)
定位删除:
1
exec sql delete from tablename [corr_name] where current of cursor_name
Eg:
1
2
3
4
5
6
7
8
9
10
11
12
13
14-- 声明游标
exec sql declare delcust cursor for
select cid from customers c where c.city='harbin' and not exists(select * from orders o where o.cid=c.cid)
-- 更新属性
for update of cid;
-- 打开游标
exec sql open delcust
-- 提取变量并删除
while(TRUE){
-- 循环提取游标内变量到宿主程序的变量
exec sql fetch delcust into :cust_id;
-- 删除当前行
exec sql delete from customers where current of delcust;
}
2) 更新
查找更新:
1
exec sql update tablename [corr_name] SET columname= expr [,columname=expr...] where search_condition
Eg:
1
exec sql update student s set sclass='035102' where s.sclass='034101‘;
定位更新:
1
exec sql update tablename [corr_name] SET columname= expr [,columname=expr...] where current of cursor_name
Eg:
1
2
3
4
5
6
7
8
9
10
11
12
13-- 声明游标
exec sql declare stud cursor for
select * from student s where s.class='034101'
-- 更新属性
for update of sclass;
-- 打开游标
exec sql open stud
while(TRUE){
-- 循环提取游标内变量到宿主程序的变量
exec sql fetch stud into :vSno,:vSname,:vSclass;
-- 更新当前行
exec sql update student set sclass='035102' where current of stud;
}
10. 宿主程序如何知道SQL语句的执行状态,是否发生错误
1) 状态:
- 是指嵌入式SQL语句的执行状态,尤其指一些出错状态,有时程序需要知道这些状态并对这些状态进行处理
2) 状态捕获及处理由三部分构成:
设置SQL通信区:
1
exec sql include sqlca;
其中SQLCA是一个已被声明过的具有C语言的结构形式的内存信息区,其中的成员变量用来记录SQL语句的执行状态,便于宿主程序读取与处理
设置状态捕获语句:
1
exec sql whenever condition action;
可设置多次
该语句会对所有由exec sql语句所引起的对数据库系统的调用自动检查它是否满足条件
condition包括 sqlerror;not found;sqlwarning ; action包括continue;goto;stop;do|call
状态捕获语句Whenever的作用范围是其后的所有exec sql 语句,直到程序中出现另一条相同条件的whenever为止
状态处理语句:
1
report_error:exec sql rollback;
某一段程序以应对SQL操作的某种状态
11. 动态SQL,依据条件动态构造SQL语句,但欲访问的表名和字段对编程者是已知的
1) 静态SQL:
SQL语句在程序中已经按要求写好,只需要把一些参数通过变量传送给嵌入式SQL语句即可
示例:
1
2SpecName='张三';
exec sql select Sno,Sname,Sclass into :vSno,:vSname,:vSclass from Student where Sname=:SpecName;
2) 动态SQL:
SQL语言可以在程序中动态构造,形成一个字符串,然后再交给DBMS执行,交给DBMS执行时仍然可以传递变量
示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#include <stdio.h>
--设置SQL通信区
exec sql include sqlca;
--变量声明
exec sql begin declare section;
char user_name[]="Scott"; char user_pwd[]="tiger";
char sqltext[]="delete from customers where cid=\'c006\'";
exec sql end declare section;
int main()
{
--设置状态捕获语句
exec sql whenever sqlerror goto report_error;
--连接数据库
exec sql connect :user_name identified by :user_pwd;
--立即执行语句
exec sql execute immediate :sqltext;
--提交事务
exec sql commit release: return 0;
--状态处理语句
report_error:print_dberror();
--撤销事务
exec sql rollback release :return 1;
}
动态SQL的两种执行方式:
立即执行语句(构造的字符串SQL内部没有变量参数):
1
exec sql execute immediate:host-variable;
运行时编译并执行
Prepare-Execute-Using语句(构造的字符串内部有变量参数):
1
2
3exec sql prepare sql_temp from :host-variable;
-----
exec sql execute sql_temp using :cond-variable;1) Prepare语句先编译,编译后的SQL语句允许动态参数
2) Execute语句执行,用using语句将动态参数传送给编译好的Sql语句
12. 数据字典(Data dictionary)
定义:
- 是系统维护的一些表或视图的集合,存储了数据库中各类对象的定义,这些信息又称数据库的元数据–关于数据的数据
内容:
- 与关系相关的信息;用户与账户信息;统计与描述性数据;物理文件组织信息;索引相关信息
Ch6. Database Design
1.E-R概念简介
1) 定义:
E-R(Entity-Relationship)模型即实体-联系模型, E-R模型可以成功描述数据库所存储的数据。
2) E-R模型的基本要素:
- 实体(Entity):
- 实体是E-R模型的基本对象,是现实世界中各种事物的抽象,凡是可以相互区别,并可以被识别的事、物概念等均可认为是实体。
- 属性(Attribute):
- 每个实体都具有各种特征,称其为实体的属性,如学生有学号,姓名,年龄等属性。实体的属性值是数据库存储的主要数据
- 可设置主键(primary key)和其他候选键(candidate key)等
- 联系(Relationship):
- 实体间会存在各种关系,如人与人之间可能存在领导与雇员关系等,实体间的关系被抽象为联系。
- 图例:
3) E-R图像关系模型的转换:
一个1:1联系可以转换成一个独立的关系模式,也可以与任意一端对应的关系模式合并。
一个1:n联系可以转换为一个独立的关系模式,也可以与n端对应的关系模式合并。
一个m:n联系转换为一个关系模式
- 三个或三个以上实体间的一个多元联系可以转换为一个关系模式。
- 具有相同码的关系可以合并。
4)关联基数
基数表示的含义:
1. Purchase Order右边的(1, 1)表示一个Purchase Order有且必须有一个Party
2. Party左边的(0, n)表示一个Party可以拥有多个Purchase Order,也可以没有
3. Purchase Order左边的(1, n)表示Purchase Order必须有一个或多个Order Line
4. Order Line右边的(1, 1)表示每个Order Lien必须属于一个Purchase Order
5. Order Line下面的(1, 1)和菱形符号一起表示每个Order Line要么是一个Product要么是一个Service
6. Product和Service上面的(0, n)表示Product和Service可以属于0个或多个Order Line
注意:
(E, R) = (x, y)中x只能为0或1;y只能为1或n
5) 用例 (将下面的E-R图转换为关系模式,关系的码用下划线标出):
- 用例1
部门(部门号,部门名,经理的职工号,…);此为部门实体对应的关系模式,该关系模式已包含了联系"领导"所对应的关系模式。经理的职工号是关系的候选码。
职工(职工号,部门号,职工名,职务,…);此为职工实体对应的关系模式,该关系模式已包含了联系“属于”所对应的关系模式。
产品(产品号,产品名,产品组长的职工号,…);此为产品实体对应的关系模式。
供应商(供应商号,姓名,…);此为供应商实体对应的关系模式 。
零件(零件号,零件名,…);此为零件实体对应的关系模式。
生产(职工号,产品号,工作天数,…);此为联系“生产”所对应的关系模式。
供应(产品号,供应商号,零件号,供应量);此为联系“联系”所对应的关系模式。
- 用例2
设有一个图书借阅管理数据库,已知:
图书的属性有书号(具有唯一性)、书名
读者的属性有借书证号(具有唯一性,每个读者只能有一个借书证号)、姓名、身份证号、住址、电话
出版社的属性有出版社名称(具有唯一性)、地址、联系电话。
其中:
每本图书只能有一个出版社出版发行
每个读者可以同时借阅多本图书,也可以在不同时候借阅同一本图书
系统需要记录每本图书被借阅的借阅日期和归还日期
请用E-R模型表示该数据库系统的概念模型,并将其转换成等价的关系模式。
2.函数依赖(FD)
1) 定义:
- 函数依赖是数据依赖的一种,它反映属性或属性组之间相依存,互相制约的关系,即反映现实世界的约束关系。
- 设R(U)是属性U上的一个关系模式,X和Y均为U={A1,A2,…,An}的子集,r为R的任一关系,如果对于r中的任意两个元组u,v,只要有u[X]=v[X],就有u[Y]=v[Y],则称X函数决定Y,或称Y函数依赖于X,记为X→Y。
示例:
(sno-学生ID,tno-教师ID,cno-课程ID,sname-学生姓名,tname-教师姓名,cname-课程名称,grade-成绩)
sno→sname, cno→cname, (sno, cno)→grade
sname→sno, tno→cno, sno→tname × (不存在一一对应关系)
2)完全函数依赖和部分函数依赖
- 在完全函数依赖:R(U)中,如果X→Y,并且对于X的任何真子集X’ , 都有X’ Y,则称Y完全依赖于X,记作X→Y;
- 在部分函数依赖:如果X→Y,且X中存在一个真子集X’ ,使得X’→Y成立,则称Y部分依赖于X。
示例:
学生ID,学生姓名,所修课程ID,课程名称,成绩
(学生ID,所修课程ID)→成绩
成绩既不能单独依赖于学生ID,也不能单独依赖于所修课程ID,因此成绩完全函数依赖于关键字。
(学生ID不能唯一决定成绩,所选修课程ID也不能唯一决定成绩,需要(学生ID,所选修课程ID)一起才能唯一决定一个成绩)。
(学生ID,所修课程ID)→学生姓名
学生ID→学生姓名
学生姓名可以依赖于关键字的一个主属性——学生ID,因此学生姓名部分函数依赖于(学生ID,所修课程ID)。
3)平凡函数依赖和非平凡函数依赖
- 非平凡 函数依赖: X Y, 但是Y X,则称X Y是非平凡的函数依赖。
- 平凡函数依赖: X Y, 但是Y X,则称X Y是平凡的函数依赖。
4)传递函数依赖
- 设X,Y,Z是关系R中互不相同的属性集合,存在X→Y(YX), Y→Z,则称Z传递函数依赖于X。
3.多值依赖
1) 定义
- 设R(U)是属性集U上的一个关系模式。X,Y,Z是U的子集,并且Z=U-X-Y。关系模式R(U)中多值依赖X→→Y成立,当且仅当对R(U)的任一关系R,给定的一对(X,Z)值有一组Y(依赖的属性集合)的值,这组值仅仅决定于X值而与Z值无关;即U=X+Y+Z,有(X,Z)→ Y,但Y仅由X唯一确定,此时记X→→Y,称多值依赖。
- 若X→→Y,而Z=φ,则称X→→Y为平凡的多值依赖。否则称X→→Y为非平凡的多值依赖;多值依赖属4NF的定义范围,比函数依赖要复杂得多,很多书上都没有讲清楚。
- 说得简单点就是:在关系模式中,函数依赖不能表示属性值之间的一对多联系,这些属性之间有些虽然没有直接关系,但存在间接的关系,把没有直接联系、但有间接的联系称为多值依赖的数据依赖。例如,教师和学生之间没有直接联系,但教师和学生可通过系名,或任课把教师和学生联系起来。
可以看出,如果把上面的一组改为一个,那么多值依赖就变成了函数依赖。当然一个值组成的组也是组,所以说,函数依赖是多值依赖的特殊情况。
2) 示例:
课程C | 教师T | 参考书B |
---|---|---|
数学 | 邓军 | 数学分析 |
数学 | 邓军 | 高等代数 |
数学 | 邓军 | 微分方程 |
分析:
表中,U = C+T+B,(C,T)确定一组B(依赖的属性集合),但是这组B其实与T无关,仅由C确定,所以(C,T)->->B。又因为T不是空集,所以(C,T)->->B为非平凡多值依赖。
要想消除多值依赖,可以分解为:(C,T), (C,B)即表1,表2
表1:
课程C | 教师T |
---|---|
数学 | 邓军 |
表2:
课程C | 参考书B |
---|---|
数学 | 数学分析 |
数学 | 高等代数 |
数学 | 微分方程 |
结论:
对于R中的每个非平凡多值依赖X->->Y(Y不属于X),X都含有候选码,则R属于4NF。
对于每一个非平凡多值依赖X->->Y,X若含有候选码,也就是X->Y,所以4NF所允许的非平凡多值依赖是函数依赖。
实例解释:
有这样一个关系 <仓库管理员,仓库号,库存产品号> ,假设一个产品只能放到一个仓库中,但是一个仓库可以有若干管理员,那么对应于一个 <仓库管理员,库存产品号>有一个仓库号,而实际上,这个仓库号只与库存产品号有关,与管理员无关,就说这是多值依赖。
(C,B)上的一个值(物理,光学原理)对应一组T值(李平,王强,刘明),这组值仅仅决定于课程C上的值,也就是说对于(C,B)上的另一个值(物理,普通物理学),它对应的一组T值仍是(李平,王强,刘明),尽管这时参考书B的值已经改变了。因此T多值依赖于C,即C→→T。
3)性质:
- 多值依赖具有对称性;即若X→→Y,则X→→Z,其中Z=U-X-Y。
- 多值依赖具有传递性;即若X→→Y,Y→→Z,则X→→Z-Y。
- 若X→→Y,X→→Z,则X→→YZ。
- 若X→→Y,X→→Z,则X→→Y∩Z。
- 若X→→Y,X→→Z,则X→→Y-Z,X→→Z-Y。
4.函数依赖的推理规则
1) 逻辑蕴涵
给定一个关系模式,只考虑给定的函数依赖是不够的,必须找出在该关系模式上成立的其他函数依赖。
逻辑蕴含:设F是关系模式R(U)的函数依赖集合,由F出发,可以证明其他某些函数依赖也成立,我们称这些函数依赖被F逻辑蕴含。"F蕴含X→Y"意味着关系实例只要满足F就满足X→Y。
例如,设F={ A→B,B→C },则函数依赖A→C被F逻辑蕴含,记作:F |= A→C。即函数依赖集 F 逻辑蕴含函数依赖A→C。
2) F的闭包F+
对于一个关系模式,如何由已知的函数依赖集合F,找出F逻辑蕴涵的所有函数依赖集合呢?这就是我们下面要讨论的问题。
F的闭包F+:设F为一个函数依赖集,F的闭包是指F逻辑蕴涵的所有函数依赖集合。 F的闭包记作F+。
示例:
给定关系模式R(A, B, C, G, H, I),函数依赖集合F={A→B,A→C,CG→H,CG→I,B→H}。
可以证明函数依赖A→H被F逻辑蕴涵。
证明:
设有元组s和t,满足s[A]=t[A],根据函数依赖的定义,由已知的A→B,可以推出s[B]=t[B]。又根据函数依赖B→H,可以有 s[H]=t[H]。因此,已经证明对任意的两个元组s和t,只要有s[A]=t[A],就有s[H]=t[H]。所以,函数依赖A→H被F逻辑蕴涵。
注意:当F很大时,计算的过程会很长。为了从已知的函数依赖推导出其它函数依赖,Armstrong 提出了一套推理规则,称为Armstrong 公理 ,通过反复使用这些规则,可以找出给定F的闭包F+。
3) Armstrong 公理
a. 定义:从已知的一些,可以推导出另外一些函数依赖的推理规则称作“Armstrong 公理”。
b. 基本公理:
自反律:如果 Y X U,则 X → Y 成立。(平凡函数依赖)
证明:
设t1, t2是关系R中的任意两个元组(t1R, t2R), 且它们在属性集X上的值相等(t1[X] = t2[X]);
由于Y是X的子集,即X Y;
因此必有t1[Y] = t2[Y]。
增广律:如果 X → Y 在 R(U) 成立,且 Z U,则 XZ [1]→ YZ成立
证明:
设 t1R, t2R, 如果 t1[XZ] = t2[XZ], 则:
t1[X] = t2[X] …………………………(1)
t1[Z] = t2[Z] …………………………(2);由(1)及X→Y得: t1[Y] = t2[Y] …………(3);
由(2)及(3)得:t1[YZ] = t2[YZ]。
传递律:如果 X → Y,Y → Z 成立,则 X → Z 成立。
证明:
设 t1R, t2R, 如果 t1[X] = t2[X] ………………(1);
由(1)及X→Y得:t1[Y] = t2[Y] ……………… (2);
由(2)及Y→Z得:t1[Z] = t2[Z]。
c. 推理规则:
(合并):{X → Y,X → Z},则 X → YZ
(分解):{X → Y,Z ∈ Y},则 X → Z(或:X → YZ,那么 X → Y,X → Z)
(伪传递):{X → Y , YW → Z},则 WX → Z
(复合):{X → Y,W → Z},则 XW → YZ
(自积律):{X → YZ,Z → W},则 X → YZW
4) Armstrong公理系统的有效性和完备性
Armstrong公理系统的有效性指的是:
由F出发根据Armstrong公理系统推导出来的每一个函数依赖一定在F+中。
Armstrong公理系统的完备性指的是:
对于F+所逻辑蕴含的每一函数依赖,必定可以由F出发根据Armstrong公理系统推导出来。
5) 属性集的闭包
原则上讲,对于一个关系模式R(U, F),根据已知的函数依赖F,反复使用前面的规则,可以计算函数依赖集合F的闭包F+。但是,利用推理规则求出其全部的函数依赖F+是非常困难的,而且也没有必要。因此,可以计算闭包的子集,即选择一个属性子集,判断该属性子集能函数决定哪些属性,这就是利用属性集闭包的概念。
定义:
设F为属性集U上的函数依赖集,X∈U,即X为U的一个子集。在函数依赖集F下被X函数决定的所有属性为F+下属性集X的闭包,记作X+。即X+={ A| X→A } 。
计算属性集闭包X+的算法如下:
输入:X,F
输出: X+迭代算法的步骤:
选取X+的初始值为X ,即X+={X};
计算X+, X+={X, Z} ,其中Z要满足如下条件:
Y是X+的真子集,且F中存在一函数依赖Y→Z。实际上就是以X+中的属性子集作为函数依赖的决定因素,在F中搜索函数依赖集,找到函数依赖的被决定属性Z放到X+中。
判断:如果X+没有变化?或X+等于U?则X+就是所求的结果,算法终止。否则转②。
因为U是有穷的,所以上述迭代过程经过有限步骤之后就会终止。
示例:
6) 极小函数依赖集(最小函数依赖集)
定义:
如果函数依赖集F满足下列条件,则称F为最小函数依赖集或最小覆盖。
F中的任何一个函数依赖的右部仅含有一个属性;
F中不存在这样一个函数依赖X→A,使得F与F-{X→A}等价;
F中不存在这样一个函数依赖X→A,X有真子集Z使得F-{X→A}∪{Z→A}与F等价。
计算最小函数依赖集的算法:
- 将F中的所有依赖右边化为单一元素
- 去掉F各函数依赖左边的冗余属性(只检查左部不是单个属性的函数依赖)
- 去掉F中所有冗余依赖关系(逐个求,在去掉某个函数依赖的F中求该函数依赖左边的闭包,如果闭包能包含右边属性,则表示这个函数依赖要去掉)
举例:
已知关系模式R<U, F>,U={A, B, C, D, E, G},F={AB→C, D→EG, C→A, BE→C, BC→D, CG→BD, ACD→B, CE→AG},求F的最小函数依赖集。
求解步骤:
1. 将F中的所有依赖右边化为单一元素
F = {AB→C, D→E, D→G, C→A, BE→C, BC→D, CG→B, CG→D, ACD→B, CE→A, CE→G}
2. 去掉F各函数依赖左边的冗余属性(只检查左部不是单个属性的函数依赖)
AB→C:
- 去掉A, B+ = B, 不包含C,A不为冗余属性,所以A不能去掉
- 去掉B, A+ = A, 不包含C,B不为冗余属性,所以B不能去掉
BE→C:
- 去掉B, E+ = E, 不包含C,B不为冗余属性,所以B不能去掉
- 去掉E, B+ = B, 不包含C,E不为冗余属性,所以E不能去掉
BC→D:
去掉B, C+ = {A,C}, 不包含D, B不为冗余属性,所以B不能去掉
去掉C, B+ = B, 不包含D, C不为冗余属性,所以C不能去掉
CG→B:
去掉C, G+ = G, 不包含B, C不为冗余属性,所以C不能去掉
去掉G, C+ = {A,C}, 不包含B, G不为冗余属性,所以G不能去掉
ACD→B:
去掉A, (CD)+ = {A, B, C, D, E, G}, 包含B, A为冗余属性,所以把A去掉,则为CD→B
去掉C, D+ = {D, E, G}, 不包含B, C不为冗余属性,所以C不能去掉
去掉D, C+ = {A, C}, 不包含B, D不为冗余属性,所以D不能去掉
CE→A:
去掉C, E+ = E, 不包含A, C不为冗余属性,所以C不能去掉
去掉E, C+ = {A, C}, 包含A, E不为冗余属性,所以把E去掉,则为C→A
与存在依赖重复,故舍去
CE→G:
去掉C, E+ = E, 不包含G, C不为冗余属性,所以C不能去掉
去掉E, C+ = {A, C}, 不包含G, E不为冗余属性,所以E不能去掉
所以:F = {AB→C, D→E, D→G, C→A, BE→C, BC→D, CG→B, CG→D, CD→B, CE→G}
3. 去掉F中所有冗余依赖关系(逐个求,在去掉某个函数依赖的F中求闭包,如果包含右边属性,则表示这个函数依赖要去掉)
AB→C:
(AB)+ = {A, B}, 不包含C, 则不用去掉
D→E:
D+ = {D, G}, 不包含E, 则不用去掉
D→G:
D+ = {D, E}, 不包含G, 则不用去掉
C→A:
C+ = C, 不包含A, 则不用去掉
BE→C:
(BE)+ = {B, E}, 不包含C, 则不用去掉
BC→D:
(BC)+ = {A, B, C}, 不包含D, 则不用去掉
CG→B:
(CG)+ = {A, B, C, D, E, G}, 包含B, 则去掉
注意:此时CG→B已被去掉,函数依赖集F需要更新后再求新的函数依赖的闭包
CG→D:
(CG)+ = {A, C, G}, 不包含D, 则不用去掉
CD→B:
(CD)+ = {A, C, D, E, G}, 不包含B, 则不用去掉
CE→G:
(CE)+ = {A, C, E}, 不包含G, 则不用去掉
故最小依赖集为:Fm= {AB→C, D→E, D→G, C→A, BE→C, BC→D, CG→D, CD→B, CE→G}
7) 超码,候选码与主码
关系:
超码包括候选码,候选码包括主码
超码:
是一个或多个属性的集合,这些属性可以让我们在一个实体集中地标识一个实体
如果K是超码,那么所有包含K的集合也是超码
候选码:
从超码中选出的,自然地,候选码也是一个或多个属性的集合;
可能大多数超码中含有多余的属性。所以我们需要候选码,不含有多余属性的超码称为候选码,候选码是可以标识一个元组的最少的属性集合。
关系中的一个超码,其值能标识一个元组,若从该超码中去掉任何一个属性,它就不具有这一性质了。(即该超码不应该存在一个真子集也能标识一个元组)。这样的属性组称作候选码。
候选码是最小超码,它们的任意真子集都不能成为超码。例如,如果K是超码,那么所有包含K的集合都不能是候选码;如果K,J都不是超码,那么K和J组成的集合(K,J)有可能是候选码。
主码:
一个表的候选码可能有多个,从这些个候选码中选择一个做为主码,至于选择哪一个候选码,这个是无所谓的,只要是从候选码中选的就行。
主属性:
一个表可以有多个候选码,那么对于某个属性来说,如果这个属性存在于所有的候选码中,它就称之为主属性。简单来说,主属性是候选码属性的并集。
非主属性:
不包含在候选码中的属性称为非主属性。 非主属性是相对于主属性来定义的。
<各类码及属性整理>
https://blog.csdn.net/sumaliqinghua/article/details/85872446
8) 求解候选码
对于给定的关系R(A1,A2,…An)和函数依赖集F,可将其属性分为4类:
L类:仅出现在函数依赖左部的属性。
R 类:仅出现在函数依赖右部的属性。
N类:在函数依赖左右两边均未出现的属性。
LR类:在函数依赖左右两边均出现的属性。
定理1:对于给定的关系模式R及其函数依赖集F,若X(X∈R)是L类属性,则X必为R的任一候选码的成员。
推论1:对于给定的关系模式R及其函数依赖集F,若X(X∈R)是L类属性,且X+包含了R的全部属性;则X必为R的唯一候选码。
定理2:对于给定的关系模式R及其函数依赖集F,若X(X∈R)是R类属性,则X不在任何候选码中。
定理3:对于给定的关系模式R及其函数依赖集F,若X(X∈R)是N类属性,则X必包含在R的任一候选码中。
推论2:对于给定的关系模式R及其函数依赖集F,若X(X∈R)是L类和N类组成的属性集,且X+包含了R的全部属性;则X是R的唯一候选码。
具体步骤:
算法描述:
将R 的所有属性分为L、R、LR 和N 四类,并令X 代表L、N 类,Y 代表LR 类。
求X+。若X+包含了R 的全部属性,则即为R 的唯一候选码,转(5);否则,转(3)。
在Y 中取一属性A,求(XA)+ ,若它包含了R 的全部属性,则是候选码,转(4);否则,调换一属性反复进行这一过程,直到试完所有Y 中的属性。
如果已找出所有候选码,则转(5);否则在Y 中依次取2 个、3 个、…,求它们的属性闭包,若其闭包包含R 的全部属性,则是候选码。
结束。
示例1:
如设有关系模式R(U), 其函数依赖集为F, 其中U={A, B, C, D, E}, F={AC, CA, BAC, DAC}
求R 的候选码。
求解方法:
根据函数依赖可得:
属性B 、D 为L 类,E 为N 类,因此属性B 、D 、E 必为候选码的成员, 且此三个属性的闭包: B+=ABC, (BD)+=ABCD, (BDE)+=ABCDE, 根据推论2 可得BDE 是R 的唯一候选码。所以R 的候选码为BDE 。
变式:如果把例题中关系模式R(U) 中的属性E 去掉,那么再求R 的候选码的话可以根据推论1得出
BD 为R 的唯—候选码。
示例2:
如设有关系模式R(U), 其函数依赖集为F, 其中U={A, B, C, D, E}, F={BA, DA, AE, ACB}
求R 的候选码。
求解方法:
根据函数依赖可得:
属性C、D 为L 类,因此属性C、D 必为候选码的成员, 且此两个属性的闭包: C+=C, (CD) +=ABCDE, 根据推论1可得CD 是R 的唯一候选码。所以R 的候选码为CD 。
注意:
快速求解方法适用于判断有属性是属于L 类、N 类或其中一种的情况下求解。如果有L 类和N类的属性, 则求解候选码速度非常快。
简而言之: L、R、N、LR 类。根据定理, L、N 类必为侯选码之一,如果L+包含全部R, 则L为唯一侯选。R 类不在任何侯选码中。L+N 类且(L+N)+包含所有R, 则L+N 为唯一侯选。(适于有L、N 类至少一种的情况。)
5.关系模式的分解
1) 无损联接
定义:
无损联接分解是将一个关系模式分解成若干个关系模式后,通过自然联接和投影等运算仍能还原到原来的关系模式,则称这种分解为无损联接分解。
示例:
关系模式:成绩(学号,姓名,课程号,课程名,分数)
函数依赖:学号->姓名,课程号->课程名, (学号,课程号)->分数
若将其分解为下面三个关系模式:
成绩(学号,课程号,分数)
学生(学号,姓名)
课程(课程号,课程名)
1. 这样的分解是无损分解吗?
学号->姓名
成绩(学号,课程号,分数,姓名)
课程号->课程名
成绩(学号,课程号,分数,姓名,课程名)
因此这个例子是无损分解的
无损分解判定算法:
建立一张k行n列的表来检验连接是否失真(第i行对应于Ri,第j列对应于属性Aj);
填表:若A属于Ri,则将第i行第j列填为aj否则填入bij;
修改表:逐一考察F中的函数依赖X -> Y,X可能包含一个或者多个属性,如果这(个)些属性对应于表中的列的值相同,则值相等的行所对应的Y属性所有的列的值也相等。(比方说X -> Y,X是A1A2所对应的属性,Y是属性A4。由第一步,如果表中第一行和第二行的值相等,那么表中A4对应的第一行和第二行的值也要修改成一样的。)如果其中有aj,则将bij改成aj;如果没有aj,就将他们都改成bij,一般来说i是值相等的行中最小的行号。
反复(指在前一次修改地基础上,反复进行直到表中的数据不再改变)进行(3),若发现某一行变成a1,a2,…aj,则可以得出分解p{(R1,F1),(R2,F2),…(Rk,Fk)}具有连接不失真性(即无损分解)
具体示例:
设R=ABCDE, R1=AD, R2=BC, R3=BE, R4=CDE, R5=AE(省略Fi,若给出Ui,则表示求Ri(Ui,Fi)), 设函数依赖:A->C, B->C, C->D, DE->C, CE->A. 判断R分解成 ρ={R1, R2, R3, R4, R5}是否无损联接分解?
1. 建表:
A B C D E AD a1 b12 b13 a4 b15 BC b21 a2 a3 b24 b25 BE b31 a2 b33 b34 a5 CDE b41 b42 a3 a4 a5 AE a1 b52 b53 b54 a5 分析:
(A B C D E)是关系R的属性, AD, BC, BE, CDE, AE 是分解之后每一个关系对应的属性集
填表的过程:
当横竖相交的时候,如果在分解关系中存在对应列的单个的属性(譬如第一列第一行AD与A相交的单元格,AD含有A,就填写a1),则填写a下标 , 下标就是单元格对应所在的列号。否则填写b下标, 下标是单元格对应所在的行列号。
2. 根据依赖关系修改原始表:
- 对于依赖关系AC,看A列中有两行a1是相等的(第一行和第五行),所以在C列中对应的两行也应该相等,但是看到这两行都是b(b13,b53),所以将这个b都换成b13(上面的较小的标)
A B C D E AD a1 b12 b13 a4 b15 BC b21 a2 a3 b24 b25 BE b31 a2 b33 b34 a5 CDE b41 b42 a3 a4 a5 AE a1 b52 b53 b13 b54 a5 - 对于依赖B C, 同样的道理,看B这一列中,第二行和第三行都是a2,那么对C这一列同样的操作,但是看到C这一列中第二行是a3,那么就将第三行改成a3,优先级比b要高。
A B C D E AD a1 b12 b13 a4 b15 BC b21 a2 a3 b24 b25 BE b31 a2 b33 a3 b34 a5 CDE b41 b42 a3 a4 a5 AE a1 b52 b13 b54 a5 - 对依赖CD,C列的1,5行相等,D的1,5行也应该相等,D的第1行有a,所以b54换成a4;另外C列的2,3,4行也相等,D的2,3,4行也应该相等,D的第4行有a,所以将对应的行都换成a4。
A B C D E AD a1 b12 b13 a4 b15 BC b21 a2 a3 b24 a4 b25 BE b31 a2 a3 b34 a4 a5 CDE b41 b42 a3 a4 a5 AE a1 b52 b13 b54 a4 a5 - 对于DEC, DE公共的相等的行是3,4,5行,对应C的3,4,5行也应该相等,故将C列最后的b13换成a3,所以表格经过这个函数依赖关系,就是:
A B C D E AD a1 b12 b13 a4 b15 BC b21 a2 a3 a4 b25 BE b31 a2 a3 a4 a5 CDE b41 b42 a3 a4 a5 AE a1 b52 b13 a3 a4 a5 - 对于CEA, CE的公共行是3,4,5行,所以将A的3,4,5行也对应相等,因为A列的第五行含有a1,所以将3,4行的b31,b41都换成a1
A B C D E AD a1 b12 b13 a4 b15 BC b21 a2 a3 a4 b25 BE b31 a1 a2 a3 a4 a5 CDE b41 a1 b42 a3 a4 a5 AE a1 b52 a3 a4 a5 - 最终得到的表格就是:
A B C D E AD a1 b12 b13 a4 b15 BC b21 a2 a3 a4 b25 BE a1 a2 a3 a4 a5 CDE a1 b42 a3 a4 a5 AE a1 b52 a3 a4 a5 3. 最后,我们从表格里看到对于BE行来说,变成a1…a5,所以得出结论,题中的分解是无损联接分解
无损分解的一个简便的判别方法(适用于分解成2个关系的情况)
例如:
有关系R=ABC, 依赖关系F = {A–>B}那么下面哪个是无损分解:
A. {R1(AB), R2(AC)}
B. {R1(AB), R3(BC)}求解方法:
1. 建表法:
选项A:
A B C AB a1 a2 b13 AC a1 b22 a3 A B C AB a1 a2 b13 AC a1 a2 a3 选项B:
A B C AB a1 a2 b13 BC b21 a2 a3 A B C AB a1 a2 b13 BC b21 a2 a3 结论:选项A的AC一行为a1…a3,故此时为无损分解;而选项B无法化成,所以不是无损分解。
2. 快速判别法:
首先看选项A,R1∩R2=A,R1-R2=B,R1∩ R2–>(R1-R2) F+.所以它是无损分解
再看选项B, R1∩R2=B, R1-R2=A, R2-R1=C,
所以它不是无损分解
快速判断无损分解的方法就是:
1. 对两个集合先求集合的∩,然后求集合的差(2个集合有两个差的结果)
如果集合的∩–>集合的差(得到差结果的任意一个) F+ 成立,那么就是无损分解2. 如果R1∩R2是R1或R2的超码,则R上的分解(R1,R2)是无损分解。这是一个充分条件,当所有的约束都是函数依赖时它才是必要条件(例如多值依赖就是一种非函数依赖的约束),不过这已经足够了。
2) 保持函数依赖
定义:
如果F上的每一个函数依赖都在其分解后的某一个关系上成立,则这个分解是保持依赖的(这是一个充分条件)。如果上述判断失败,并不能断言分解不是保持依赖的,还要使用下面的通用方法来做进一步判断。
设F是关系模式R的函数依赖集,ρ={R1<U1,F1>, R2<U2,F2>,…, Rk<Uk,Fk>}为R的一个分解,如果Fi=πRi(F)(Fi为函数依赖集F在Ri上的投影)的并集(F1∪F2∪…∪Fk) ≡ F(i=1,2,…,k),则称分解ρ具有函数依赖保持性。
保持依赖判定算法:
对F上的每一个α→β使用下面的过程:
result:=α;
while(result发生变化)do
for each 分解后的Ri
t=(result∩Ri)+∩Ri
result=result∪t
- 这里的属性闭包是在函数依赖集F下计算出来的。如果result中包含了β的所有属性,则函数依赖α→β。分解是保持依赖的当且仅当上述过程中F的所有依赖都被保持。
函数依赖保持判断方法:
- 先找到要分解的目标Ri(Ui),然后求出Ui+;
- 接着在F中找到所有包含Ui+属性的关系 ;
- 挑选或推导出仅含有Ri(Ui)中属性的关系,组成即为Fi ;
示例:
1. 将R = (ABCD,{A→B,B→C,B→D,C→A})分解为关于U1=AB,U2=ACD两个关系(给出Ui,则表示求Ri(Ui,Fi)),求R1、R2,
并检验分解的无损联接性和分解的函数依赖保持性。求解方法:
1. 无损分解:
F1 = πR1(F) = {A→B, B→A},
F2 = πR2(F) = {A→C, C→A, A→D}注意:Fi为仅含有Ui中元素,且在F上的所有关系(包含推导关系)
R1 = (AB, {A→B, B→A})
R2 = (ACD, {A→C, C→A, A→D})U1∩U2 = AB∩ACD = A,
U1-U2 = AB-ACD = B, A→B∈F,
所以ρ是无损分解;
2. 函数依赖性:
F1UF2 = {A→B, B→A, A→C, C→A, A→D} ≡ {A→B, B→C, B→D, C→A} = F;
Tip:可用定理对函数依赖进行化简,观察并集是否为F;
所以ρ具有函数依赖保持性。
2. 关系模式R(A, B, C ,D,{F}) 中函数依赖集F = {A→B, C→D}, ρ = {R1(AB,{F1}),R2(CD,{F2})},求R1, R2 并检验分解的无损联接性和分解的函数依赖保持性。
求解方法:
1. 无损分解:
F1 = πR1(F) = {A→B},
F2 = πR2(F) = {C→D}
R1(AB, {A→B}),
R2(CD, {C→D})
U1∩U2 = AB∩CD = Φ,
U1-U2 = AB,
U2-U1 = CD,
Φ→ABF,
Φ→CDF,所以ρ不是无损分解;
2. 函数依赖性:
F1UF2 = {A→B,C→D} = F
所以ρ具有函数依赖保持性。
3. 已知关系模式R(CITY, ST, ZIP), F = {(CITY, ST)→ZIP, ZIP→CITY},以及R上的一个分解ρ = {R1(U1,F1), R2(U2,F2)}, R1 = {ST, ZIP}, R2 = {CITY, ZIP},求R1, R2 ,并检验分解的无损联接性和分解的函数依赖保持性。
求解方法:
1. 无损分解:
F1= πR1(F) = {Φ},
F2 = πR2(F) = {ZIP→CITY}R1 = ({ST, ZIP}, {Φ}),
R2 = (CITY, ZIP, {ZIP→CITY})
U1∩U2 = {ST, ZIP}∩{CITY, ZIP} = ZIP,
U1-U2 = ST,
U2-U1 = CITY,ZIP→CITY∈F,所以ρ是无损分解;
2. 函数依赖性:
F1UF2 = {ZIP→CITY}{(CITY, ST)→ZIP, ZIP→CITY} = F
所以ρ不具有函数依赖保持性。
总结:
- 无损分解:R Ri
- 函数依赖:F Fi
- 函数依赖和无损分解间没有必然的联系
6.关系模式的范式(NF)
1)定义
范式xNF即是满足特定要求的模式,将低一级范式的关系模式通过模式分解转换为高一级范式的关系模式集合的过程叫做规范化;
范式从低级到高级依次为:1NF、2NF、3NF、BCNF、4NF、5NF,高一级的范式总是低一级范式的真子集。
根据关系模式R的不可约函数依赖集F,可以画出节点是属性或属性集,边是由被依赖节点指向依赖节点的有向图来辅助分析关系模式,叫做函数依赖图
从范式所允许的函数依赖方面进行比较,四种范式之间的关联如下图所示。
2)各类范式及其说明
第一范式(1NF)(确保每列保持原子性)
第一范式是最基本的范式。如果数据库表中的所有字段值都是不可分解的原子值,就说明该数据库表满足了第一范式。
第一范式的合理遵循需要根据系统的实际需求来定。比如某些数据库系统中需要用到“地址”这个属性,本来直接将“地址”属性设计成一个数据库表的字段就行。但是如果系统经常会访问“地址”属性中的“城市”部分,那么就非要将“地址”这个属性重新拆分为省份、城市、详细地址等多个部分进行存储,这样在对地址中某一部分操作的时候将非常方便。这样设计才算满足了数据库的第一范式,如下表所示:
第二范式(2NF)(确保表中的每列都和主键相关)
第二范式在第一范式的基础之上更进一层。第二范式需要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言)。也就是说在一个数据库表中,一个表中只能保存一种数据,不可以把多种数据保存在同一张数据库表中。
示例1:
设有关系模式R(学号S#,课程号C#,成绩G,任课教师TN,教师专长TS),基于R的函数依赖集F={(S#, C#)→G, C#→TN, TN→TS},判断R是否为2NF。
函数依赖图:
阿氏推理规则:
由F可推出:(S#, C#)→{S#, C#, G, TN, TS},即属性组合(S#, C#)是R的候选关键字(R只有这一个候选键)。(S#, C#)的一个值可惟一标识R中的一个元组(并且没有多余的属性)。
在R中,S#, C#是主属性;其余的属性G, TN, TS为非主属性。
借助上面的图,我们可以看到,非主属性G对键是完全依赖:(S#, C#)→G。但非主属性TN, TS对键是部分依赖(他们仅依赖于键的真子集C#)。由于R中存在非主属性对候选键的部分依赖,所以关系模式R不是2NF。
注意:
R中存在非主属性对候选键的部分依赖,将会引起插入异常、删除异常、更新异常和数据冗余等问题。可以把关系R无损联接地分解成两个2NF的关系模式:
ρ = {R1, R2},R1 = {S#, C#, G}, R2 = {C#, TN, TS}。
具体步骤:
- 找出R中所有的候选码(X…Y),即(X…Y)+ = F;
- 得到非主属性,并根据2NF定义判断是否满足2NF;
示例2:
选课关系 R(SNO,CNO,GRADE,CREDIT)其中SNO为学号, CNO为课程号,GRADEGE 为成绩,CREDIT 为学分。
求解方法:
由以上条件,关键字为组合关键字(SNO,CNO)
原因:非关键字属性CREDIT仅函数依赖于CNO,也就是CREDIT部分依赖组合关键字(SNO,CNO)而不是完全依赖。
解决方法:分成两个关系模式 R1(SNO,CNO,GRADE),R2(CNO,CREDIT)。新关系包括两个关系模式,它们之间通过R1中的外关键字CNO相联系,需要时再进行自然联接,恢复了原来的关系
第三范式(3NF)(确保每列都和主键列直接相关,而不是间接相关;即去除非主属性对于候选关键字的传递依赖)
如果关系模式R为2NF,并且R中的每一个非主属性都不传递依赖于R的某个候选关键字,则称R是第三范式的,简记为3NF。
示例1:
续上例R(学号S#, 课程号C#, 成绩G, 任课教师TN, 教师专长TS),判断关系模式R1 = {S#, C#, G}, R2 = {C#, TN, TS} 是否为3NF。
求解方法:
在关系模式R1={S#,C#,G},候选关键字是(S#,C#),主属性是S#,C#,非主属性是G,函数依赖为(S#,C#)→G。 由于R1中不存在非主属性对候选关键字的传递依赖,所以关系模式R1是3NF。
在关系模式R2={C#,TN,TS},候选关键字是C#,主属性是C#,非主属性是TN,TS,函数依赖为C#→TN,TN→TS。由于R2中存在非主属性对候选关键字的传递依赖C# ,TS,所以关系模式R2不是3NF。
可以把关系R2无损联接地分解成两个3NF的关系模式:
ρ={R3,R4},R3={C#,TN},R4={TN,TS}。
示例2:
若关系模式SD(SNO,SNAME,DNO,DNAME,LOCATION) 各属性分别代表学号,
姓名,所在系,系名称,系地址。 判断关系模式SD是否为3NF。求解方法:
- 关键字SNO决定各个属性。由于是单个关键字,没有部分依赖的问题,是2NF。
- 原因:关系中存在传递依赖造成的。关键字 SNO 对 LOCATION 函数决定是通过传递依赖:SNO -> DNO,及DNO -> LOCATION实现的。也就是说,SNO不直接决定非主属性LOCATION,不是3NF。
- 解决目的:每个关系模式中不能留有传递依赖。
- 解决方法:分为两个关系 S(SNO,SNAME,DNO),D(DNO,DNAME,LOCATION)
注意:
- 关系S中不能没有外关键字DNO;否则两个关系之间失去联系;
- 分解为3NF时注意保留外关键字。
- 关键字SNO决定各个属性。由于是单个关键字,没有部分依赖的问题,是2NF。
Boyce-Codd范式(BCNF)(3NF基础上去除主属性对于候选关键字的传递依赖)
如果关系模式R为1NF,并且R中的每一个函数依赖X→Y(YÏX),必有X是R的超关键字,则称R是Boyce-Codd范式的,简记为BCNF。
BCNF特性:
- 所有非主属性对键是完全函数依赖;
- 所有主属性对不包含它的键是完全函数依赖;
- 没有属性完全函数依赖于非键的任何属性组合
- 综上即为:消除了主属性对于候选关键字的部分和传递函数依赖;
与2NF,3NF的定义不同,BCNF的定义直接建立在1NF的基础上。但实质上BCNF是3NF的改进形式。3NF仅考虑了非主属性对键的依赖情况,BCNF把主属性对键的依赖情况也包括进去。BCNF要求满足的条件比3NF所要求的更高。如果关系模式R是BCNF的,那么R必定是3NF,反之,则不一定成立。
示例1:
续前例R(学号S#, 课程号C#, 成绩G, 任课教师TN, 教师专长TS),判断两个3NF关系模式R3 = {C#, TN},R4 = {TN, TS}是否为BCNF。
求解方法:
在关系模式R3中有函数依赖C#→TN,决定因素C#是R3的键;
在关系模式R4中有函数依赖TN→TS,决定因素TN是R4的键;
R3,R4都满足BCNF的定义,所以,这两个关系模式都是BCNF。
示例2:
配件管理关系模式 WPE(WNO,PNO,ENO,QNT)分别表仓库号,配件号,职工号,数量。
有以下条件:
a.一个仓库有多个职工。
b.一个职工仅在一个仓库工作。
c.每个仓库里一种型号的配件由专人负责,但一个人可以管理几种配件。
d.同一种型号的配件可以分放在几个仓库中。求解方法:
分析:
由以上得 PNO 不能确定QNT,由组合属性(WNO,PNO)来决定,存在函数依赖(WNO,PNO) -> QNT。由于每个仓库里的一种配件由专人负责,而一个人可以管理几种配件,所以有组合属性(WNO,PNO)才能确定负责人,有(WNO,PNO)-> ENO。因为 一个职工仅在一个仓库工作,有ENO -> WNO。由于每个仓库里的一种配件由专人负责,而一个职工仅在一个仓库工作,有 (ENO,PNO)-> QNT。
候选关键字:
因为(WNO,PNO) -> QNT,(WNO,PNO)-> ENO ,因此 (WNO,PNO)可以决定整个元组,是一个候选关键字。根据ENO->WNO,(ENO,PNO)->QNT,故(ENO,PNO)也能决定整个元组,为另一个候选关键字。属性ENO,WNO,PNO 均为主属性,只有一个非主属性QNT。它对任何一个候选关键字都是完全函数依赖的,并且是直接依赖,所以该关系模式是3NF。
主属性:
因为ENO->WNO,主属性ENO是WNO的决定因素,但是它本身不是关键字,只是组合关键字的一部分。这就造成主属性WNO对另外一个候选关键字(ENO,PNO)的部分依赖,因为(ENO,PNO)-> ENO,但反过来不成立,而ENO->WNO,故(ENO,PNO)-> WNO 也是传递依赖。
虽然没有非主属性对候选关键字的传递依赖,但存在主属性对候选关键字的传递依赖,同样也会带来麻烦。如一个新职工分配到仓库工作,但暂时处于实习阶段,没有独立负责对某些配件的管理任务。由于缺少关键字的一部分PNO而无法插入到该关系中去。又如某个人改成不管配件了去负责安全,则在删除配件的同时该职工也会被删除。
解决办法:
分成管理EP(ENO,PNO,QNT),关键字是(ENO,PNO);工作EW(ENO,WNO),关键字是ENO
缺点:
分解后函数依赖的保持性较差。如此例中,由于分解,函数依赖(WNO,PNO)-> ENO 丢失了, 因而对原来的语义有所破坏。没有体现出每个仓库里一种部件由专人负责。有可能出现 一部件由两个人或两个以上的人来同时管理。因此,分解之后的关系模式降低了部分完整性约束。
总结:
化简为BCNF:
- 先将关系模式化简为3NF;
- 再找出所有候选关键字及其主属性;
- 接着根据函数依赖关系判断是否存在主属性对候选关键字的传递依赖或部分依赖;
- 最后将造成传递依赖或部分依赖的关系模式分解出去;
7.关系模式分解为范式的分解算法
1)无损连接且保持函数依赖地分解R到3NF
示例1:
U = (A, B, C, D, E, G), F = {BG->C,BD->E,DG->C,ADG->BC,AG->B,B->D} 若R不是3NF,将R分解为无损且保持函数依赖的3NF。
求解方法:
1. 先求出候选码:
- 分为L类,N类,R类;
- 按求候选码规则求得候选码为AG
2. 再求出最小依赖集Fm:
- 将F中的所有依赖右边化为单一元素
- 去掉F各函数依赖左边的冗余属性
- 去掉F中所有冗余依赖关系
- 求得Fm = {B->E,DG->C,AG->B,B->D}
3. 左部相同原则分组:
- 对Fm按具有相同左部的原则分组,然后左部∪右部。
- U1 = B∪DE = BDE ; U2 = DGC ; U3 = AGB
4. 看有没有包含关系,有的话,合并吸收。
- 将R分解为ρ = { R1({B, D, E},{B->E, B->D}),R2({C, D, G},{DG->C}),R3({A, B, G},{AG->B}) }
- 不存在包含关系
5. 看分的属性组里有没有包含码,包含了,就是无损且保持函数依赖的3NF,没有包含,就不是无损且保持函数依赖的3NF,就加一个分组,把码加进去。
- 因为候选键AG在U3中,所以所求分解ρ具有无损连接性,并保持函数依赖,且每个子模式为3NF。
示例2:
U=(A, B, C, D, E) , F = {AB->C,C->B,D->E,D->C} 若R不是3NF,将R分解为无损且保持函数依赖的3NF。
求解方法:
1. 先求出候选码:
- 分为L类,N类,R类;
- 按求候选码规则求得候选码为AD
2. 再求出最小依赖集Fm:
- 将F中的所有依赖右边化为单一元素
- 去掉F各函数依赖左边的冗余属性
- 去掉F中所有冗余依赖关系
- 求得Fm = {AB->C,C->B,D->E,D->C}
3. 左部相同原则分组:
- 对Fm按具有相同左部的原则分组,然后左部∪右部。
- U1 = ABC ; U2 = BC ; U3 = DCE
4. 看有没有包含关系,有的话,合并吸收。
将R分解为ρ = { R1((A, B, C),{AB->C}),R2((B, C),{C->B}),R3((C, D, E),{D->E, D->C}) }
合并吸收:ρ = { R1((A, B, C),{AB->C, C->B}),R2((C, D, E),{D->E, D->C}) }
5. 看分的属性组里有没有包含码,包含了,就是无损且保持函数依赖的3NF,没有包含,就不是无损且保持函数依赖的3NF,就加一个分组,把码加进去。
- 不是无损连接,添加码。
- R3((A, D),{∅})
- 所以ρ = { R1((A, B, C),{AB->C,C->B}),R2((C, D, E),{D->E, D->C}),R3((A, D),{∅}) }
2)无损联接地分解R到BCNF
示例:
关系模式R<U, F>, 有U = {A, B, C, D, E, G}, F = {B->G, CE->B, C->A, CE->G, B->D, C->D}
求解方法:
1. 先求出候选码:
分为L类,N类,R类;
按求候选码规则求得候选码为CE
2. 再求出最小依赖集Fm:
- Fm = {B->G, CE->B, C->A, B->D, C->D}。
3. 循环分解函数依赖集:
- 开始找左部不包含CE的关系模式,第一个为B->G,
- 将其分为R1 = {(BG), {B->G}} 与R2 = {(ABCDE), {CE->B, C->A, B->D, C->D}}。
- 注意G不能出现在R2中,要根据与G相关的关系模式进行替代。
- 求R1与R2的最小函数依赖集,步骤均是按照上述算法严格进行的。
- R1,R2最小函数依赖集是其本身。
- 然后再进行分解,R1符合BCNF,继续分解R2:
- B->D,左部不含码,于是分解为R2={(BD), {B->D}},R3={(ABCE),{CE->B, C->A}}。
- R2,R3的最小函数依赖集均是其本身。
- 于是BCNF分解的最后结果为{(BG), (BD), (ABCE)}。
XZ表示X Z, YZ表示Y Z ↩︎