数据库函数依赖、闭包、超键与候选键完全指南
一、函数依赖(Functional Dependency)
定义
- 符号:
X → Y - 含义:X函数决定Y,或者说Y函数依赖于X
- 形式化定义:对于关系R的任意两个元组t1和t2,如果t1[X] = t2[X],则t1[Y] = t2[Y]
关键理解
- 箭头方向:从决定因素指向依赖因素
- 正确理解:X → Y 表示"X决定Y"或"Y依赖于X"
- 错误理解:X → Y 不是"X依赖于Y"
示例
{学号} → {姓名} 表示:
- 学号决定姓名
- 姓名依赖于学号
- 相同学号对应相同姓名
二、属性集闭包(Closure of Attributes)
定义
给定属性集S和函数依赖集F,S⁺表示通过F中的函数依赖能够推导出的所有属性的集合。
闭包算法
输入:属性集S,函数依赖集F 输出:S⁺
步骤:
- 初始化 result = S
- 重复直到result不再变化:
- 对每个FD X → Y ∈ F:
- 如果 X ⊆ result:
- result = result ∪ Y
- 如果 X ⊆ result:
- 对每个FD X → Y ∈ F:
- 返回result
示例计算
已知:R(X,Y,U,V,W),F = {X→Y, U,V→W, V→X}
计算过程:
-
{X}⁺:
- 初始:{X}
- X→Y:加入Y → {X,Y}
- 停止
- {X}⁺ = {X,Y}
-
{V}⁺:
- 初始:{V}
- V→X:加入X → {V,X}
- X→Y:加入Y → {V,X,Y}
- 停止
- {V}⁺ = {V,X,Y}
三、超键(Superkey)与候选键(Candidate Key)
超键定义
能唯一标识关系中每个元组的属性集。
判断条件:S⁺ = 所有属性
候选键定义
最小的超键(不含多余属性的超键)。
判断条件:
- S⁺ = 所有属性(超键条件)
- S的任何真子集都不是超键(最小性条件)
关系说明
- 所有候选键都是超键
- 不是所有超键都是候选键
- 一个关系可能有多个候选键
- 主键是选定的一个候选键
四、系统化寻找候选键的方法
步骤1:属性分类
基于函数依赖集F:
- L:只出现在FD左边的属性
- R:只出现在FD右边的属性
- LR:在左右都出现的属性
- N:不出现在任何FD中的属性
步骤2:从(L ∪ N)开始
- 计算(L ∪ N)⁺
- 如果(L ∪ N)⁺ = 所有属性,则(L ∪ N)是候选键
- 否则,逐步添加LR中的属性
步骤3:验证最小性
对于每个找到的超键S:
- 检查S的每个真子集S'
- 如果存在S'⁺ = 所有属性,则S不是候选键
五、详细例题解析
例题1:基础闭包计算
已知:R(A,B,C,D,E),F = {A→BC, CD→E, B→D, E→A} 求:{A}⁺、{B}⁺
解:
-
{A}⁺:
- {A} → A→BC → {A,B,C}
- {A,B,C} → B→D → {A,B,C,D}
- {A,B,C,D} → CD→E → {A,B,C,D,E}
- {A}⁺ = {A,B,C,D,E}
-
{B}⁺:
- {B} → B→D → {B,D}
- 无法再加入其他属性
- {B}⁺ = {B,D}
例题2:单候选键情况
已知:R(A,B,C,D),F = {A→B, B→C, C→D, D→B} 求:所有候选键
解:
-
计算单属性闭包:
- {A}⁺ = {A,B,C,D} ⇒ 超键
- {B}⁺ = {B,C,D} ≠ 所有属性
- {C}⁺ = {B,C,D} ≠ 所有属性
- {D}⁺ = {B,C,D} ≠ 所有属性
-
验证最小性:
- A是单属性,没有真子集
- {A}是候选键
-
结论:唯一候选键是{A}
例题3:多候选键情况
已知:R(A,B,C,D),F = {AB→C, C→D, D→A} 求:所有候选键
解:
-
属性分类:
- L: {B}(只出现在左边AB→C中)
- R: ∅
- LR: {A,C,D}(都出现在左右)
- N: ∅
-
从{B}开始:
- {B}⁺ = {B} ⇒ 不是超键
-
测试组合:
-
{A,B}⁺:
- {A,B} → AB→C → {A,B,C}
- {A,B,C} → C→D → {A,B,C,D}
- {A,B}⁺ = 所有属性 ⇒ 候选键
-
{B,C}⁺:
- {B,C} → C→D → {B,C,D}
- {B,C,D} → D→A → {A,B,C,D}
- 但{C}⁺ = {C,D,A} = 所有属性 ⇒ {B,C}不是候选键
-
{B,D}⁺:
- {B,D} → D→A → {A,B,D}
- {A,B,D} → AB→C → {A,B,C,D}
- 检查最小性:{B}⁺、{D}⁺都不是超键 ⇒ 候选键
-
{C}⁺:
- {C} → C→D → {C,D}
- {C,D} → D→A → {A,C,D}
- {C}⁺ = {A,C,D} ≠ 所有属性?错误! 实际上:{C} → C→D → {C,D} → D→A → {A,C,D} 但{A,C,D}中无法得到B,所以{C}⁺ = {A,C,D} ≠ 所有属性
修正:
- {C}⁺ = {A,C,D} ≠ 所有属性 ⇒ 不是候选键
-
-
最终候选键:{A,B}、{B,D}
例题4:判断FD是否蕴含
已知:F = {A→B, BC→D} 问:A→D是否被F逻辑蕴含?
解:
- 计算{A}⁺:
- {A} → A→B → {A,B}
- 停止(BC→D的左边BC不包含于{A,B})
- {A}⁺ = {A,B}
- D ∉ {A}⁺ ⇒ A→D不被F蕴含
六、SQL验证候选键
检查属性集S是否为超键
-- 如果返回空结果,则S唯一(可能是超键)
SELECT S
FROM R
GROUP BY S
HAVING COUNT(*) > 1;