基于函数依赖确定候选键及学生关系数据库系列技术问题
1. 怎么通过函数依赖确定候选键?
其实核心就是找能唯一标识表中所有属性的最小属性集合,步骤我给你捋清楚:
- 先把属性分成三类:
- 「左部专属属性」:只在函数依赖箭头左边出现的属性——这些肯定得进候选键,因为没有其他属性能决定它们。
- 「右部专属属性」:只在箭头右边出现的属性——绝对不可能出现在候选键里,因为它们只能被其他属性决定。
- 「双向属性」:既在左又在右的属性——得试了才知道要不要加进候选键。
- 先把所有左部专属属性凑一起,算它们的闭包(就是通过函数依赖能推导出的所有属性)。如果闭包包含了表中所有属性,那接下来要验证是不是最小的:随便去掉一个属性,闭包就覆盖不了所有属性,那这个集合就是候选键。
- 如果左部属性的闭包不够用,就逐个加双向属性进去试,直到找到最小的能覆盖所有属性的集合就行。
举个简单例子:比如表R(A,B,C,D),依赖集F={A→B, C→D, AC→B},左部专属属性是A和C,它们的闭包AC⁺={A,B,C,D},而且去掉A的话C⁺只有{C,D},去掉C的话A⁺只有{A,B},都不行,所以AC就是候选键。
2. Student关系相关任务解答
先明确下:Student表的属性是Student(I,G,P,M,S,Y,E,L,R,C),结合问题(c)的提示,我默认用学生选课场景的常见依赖集F:{I→G, I→P, PMSY→L, PMSY→R, PMSY→E, PMSY→C}(这里I是学号,G性别,P专业,M课程,S学期,Y年份,E成绩,L上课地点,R任课教师,C学分)。如果你的依赖集不一样,结果可能会有调整,先按这个来。
(a) 推导候选键
先分属性:
- 左部专属属性:I、M、S、Y(I只在依赖左边,M/S/Y在
PMSY→...的左边) - 右部专属属性:G、P、L、R、E、C(只在依赖右边)
- 没有双向属性。
先算ISMY的闭包:ISMY⁺ = I能推导出G和P,加上M、S、Y之后,就能触发PMSY→L/R/E/C,所以最终能覆盖所有属性{I,G,P,M,S,Y,E,L,R,C}。
接下来验证最小性:
- 去掉I:SMY的闭包只能拿到M、S、Y,推不出G、P,更触发不了后续依赖,不行。
- 去掉M/S/Y任意一个:都凑不齐
PMSY,推不出L/R/E/C,闭包不完整,不行。
那有没有第二个候选键?目前这个依赖集里没有,因为其他组合比如PMSY的闭包缺I和G,根本覆盖不了所有属性。如果要找第二个候选键,得补充额外的函数依赖(比如P→I这种,但现实中学号是唯一标识学生的,专业不可能决定学号,所以不太合理)。所以结论是:基于常见依赖集,该关系的唯一候选键是ISMY;若要得到第二个候选键,需要补充更多函数依赖条件。
(b) 判断所属范式
先回忆范式的核心要求:
- 1NF:所有属性都是原子值(不能是集合、嵌套结构),这里默认所有属性都满足,所以肯定是1NF。
- 2NF:消除非主属性对候选键的部分依赖(就是非主属性只依赖候选键的一部分,而不是整个候选键)。
咱们的候选键是ISMY,非主属性G、P只依赖I(候选键的子集),这就是典型的部分依赖。所以这个关系不满足2NF,最终属于1NF。
(c) 用MSY→LRCE替代PMSY→LRCE的含义
原来的依赖PMSY→LRCE意思是:专业+课程+学期+年份这四个属性一起,才能决定上课地点、教师、成绩、学分。替换成MSY→LRCE之后,就变成了课程+学期+年份这三个属性就能决定这些内容,这传递了一个很明确的业务含义:
同一门课程在同一个学期、同一年里,不管是哪个专业的学生选,上课的地点、任课教师、学分都是完全一样的——也就是说这门课没有分专业授课的安排,所有专业的学生上的是同一批课。
(如果E是学生成绩的话,这个依赖其实不太合理,因为成绩应该是和学生绑定的,所以可能E是课程的固定属性比如考核方式?不过不管怎样,核心就是专业P不再影响这些属性的决定了)
(d) 找最小覆盖(不可约函数依赖集)
最小覆盖要满足三个条件:每个依赖的右部是单属性、左部没有冗余属性、没有多余的依赖。咱们一步步来:
- 拆分右部为单属性:默认的F里每个依赖右部都是单属性(比如
PMSY→L而不是PMSY→LRCE),这一步已经满足。 - 检查左部冗余:
- 对于
PMSY→L,试着去掉P:MSY的闭包拿不到L,所以P不能删;去掉M/S/Y同理,闭包都拿不到L,所以左部没有冗余。其他PMSY→R/E/C也是一样的道理。 - 对于
I→G和I→P,左部只有I,肯定没有冗余。
- 对于
- 检查冗余依赖:
- 去掉
I→G,剩下的依赖推不出I→G,所以这个依赖不能删;I→P同理。 - 去掉
PMSY→L的话,也推不出这个依赖,所以四个PMSY开头的依赖都不能删。
- 去掉
所以最终的最小覆盖就是:{I→G, I→P, PMSY→L, PMSY→R, PMSY→E, PMSY→C}。
如果是替换成MSY→LRCE后的依赖集,拆分后是{I→G, I→P, MSY→L, MSY→R, MSY→E, MSY→C},同样检查后,这个就是它的最小覆盖。
(e) 关系分解(达到3NF标准)
咱们的目标是消除部分依赖和传递依赖,拆成满足3NF的表,而且要保证无损分解、保持函数依赖:
- 拆分学生基本信息:因为G、P只依赖I,所以单独拆出
Student_Info(I, G, P),主键是I,依赖I→G, I→P,满足3NF。 - 拆分课程安排信息:原来的
PMSY→L/R/C是专业+课程+学期+年份决定的上课安排,拆出Course_Schedule(P, M, S, Y, L, R, C),主键是PMSY,满足3NF。 - 拆分学生选课成绩:成绩E是学生选课后的属性,依赖学号+课程+学期+年份,拆出
Student_Course(I, M, S, Y, E),主键是ISMY,满足3NF。
如果是替换成MSY→LRCE后的情况,Course_Schedule可以改成Course_Schedule(M, S, Y, L, R, C),主键是MSY,其他两个表不变,这样三个表都满足3NF,而且完全保留了原来的函数依赖关系。
内容的提问来源于stack exchange,提问作者Darsolation

