通俗理解:平凡/非平凡/完全/部分函数依赖 & 范式

函数依赖

函数依赖可以理解为

        通过一个属性可以唯一确定另一个属性的值

举例:

  1. ISBN -> 书名,作者,出版社

    意思是:如果你知道一本书的 ISBN,就能唯一确定这本书的 书名作者出版社。因为 ISBN 是每本书独一无二的。
  2. 书名 -> 作者

    假设图书馆只存一本书的一个版本,那么知道一本书的 书名,你也就知道了这本书的 作者。例如:
    • "西游记" -> "吴承恩"
    • "红楼梦" -> "曹雪芹"
  3. 书名 -> 出版社

    如果每本书只有一个版本(只有一个出版社出版),那么知道 书名 就可以确定 出版社。但如果一本书有多个版本(不同出版社出版),这个依赖就不成立了。
  4. 知道身份证号(类似主键),就知道一个人的所有信息。
  5. 知道车牌号,就能找到车辆的注册信息。

平凡函数依赖

定义:如果一个函数依赖的右边属性是左边属性的子集,称为平凡函数依赖。

换句话说,你知道的本来就包括右边的信息,这没什么意义

在图书馆的图书表中(属性:ISBN, 书名, 作者, 出版社):

  1. (ISBN, 书名) → 书名

    • 这是平凡函数依赖,因为右边的 书名 已经包含在左边的属性 (ISBN, 书名) 中。
    • 换句话说:既然你已经知道 ISBN 和书名了,书名当然是确定的,这没什么新信息。
  2. (书名, 作者) → 作者

    • 这也是平凡函数依赖,因为右边的 作者 是左边的一个属性。

非平凡函数依赖

定义:如果一个函数依赖的右边属性不是左边属性的子集,称为非平凡函数依赖。

换句话说,右边的属性依赖于左边的信息,是新得出的结论

  1. ISBN → 书名

    • 这是非平凡函数依赖,因为 书名 不属于左边的属性(ISBN)。
    • 意义在于:通过 ISBN,你可以唯一确定书名。
  2. 书名 → 作者

    • 如果每本书只有一个作者,这就是非平凡函数依赖。
    • 意义在于:通过书名,可以确定作者。

完全函数依赖

定义:在一个复合键(由多个属性组成的键)中,如果右边的属性完全依赖于整个键,而不是键的一部分,这种依赖关系称为完全函数依赖。

假设图书馆的表有以下属性:

  • (ISBN, 分馆) → 馆藏数量
    • ISBN:图书的国际标准书号。
    • 分馆:图书馆的分馆名称。
    • 馆藏数量:某分馆的某本书的库存量。

这里 (ISBN, 分馆) 是复合键。

  1. 完全函数依赖:

    (ISBN, 分馆) → 馆藏数量

        要确定某本书的馆藏数量,你需要同时知道 ISBN分馆,缺一不可。例如:ISBN =         "12345",分馆 = "A馆",对应馆藏数量是 10;如果只知道 ISBN,你无法确定分馆的馆藏数量。

        这就是完全函数依赖,因为馆藏数量依赖于整个复合键 (ISBN, 分馆),而不是键的一部分。


部分函数依赖

定义:在一个复合键中,如果右边的属性依赖于复合键的一部分(而不是整个键),这种依赖关系称为部分函数依赖。

假设同样的图书馆表中:

  1. 部分函数依赖

    ISBN → 书名

        知道 ISBN 就能确定书名,而与分馆无关。

        例如:ISBN = "12345",书名是《红楼梦》。书名只依赖 ISBN,而不依赖复合键的另一部分 分馆

范式

假设一个学生选课系统,有以下初始表:

学号 学生姓名 学院 课程名 任课老师 教室
1001 张三 计算机学院 数据库 王老师 A101
1002 李四 数学学院 高数 李老师 B202
1001 张三 计算机学院 高数 李老师 B202

第一范式(1NF)——消除重复数据,所有列的值必须是原子值

  • 要求:表中的每一列只能存储单一值,不能是列表或集合。也就是说,数据必须是“原子化”的。

不符合1NF的情况:

学号 学生姓名 学院 课程名 任课老师 教室
1001 张三 计算机学院 数据库, 高数 王老师, 李老师 A101, B202

这里的“课程名”、“任课老师”、“教室”列中存储了多个值,不是原子化的。

1NF 转换:

将每个课程分成单独的记录:

学号 学生姓名 学院 课程名 任课老师 教室
1001 张三 计算机学院 数据库 王老师 A101
1002 李四 数学学院 高数 李老师 B202
1001 张三 计算机学院 高数 李老师 B202

1NF 解决了数据的非原子化问题。


第二范式(2NF)——消除部分依赖

  • 要求:表必须满足 1NF,且非主属性完全依赖于主键,不能存在部分函数依赖。

在上面的例子中主键是 (学号, 课程名)(因为“学号+课程名”唯一标识一条记录),我们发现:

  1. 学生姓名和学院只依赖于“学号”,而不依赖于复合主键的“课程名”部分(部分依赖)。
  2. 这会导致冗余:如果同一个学生选了多门课,学生的姓名和学院信息会重复存储。

2NF 转换:

拆分表,消除部分依赖:

  1. 学生信息表(只存储与“学号”相关的信息):

    学号 学生姓名 学院
    1001 张三 计算机学院
    1002 李四 数学学院
  2. 选课信息表(只存储与“学号+课程名”相关的信息):

    学号 课程名 任课老师 教室
    1001 数据库 王老师 A101
    1001 高数 李老师 B202
    1002 高数 李老师 B202

2NF 解决了部分函数依赖,减少了数据冗余。


第三范式(3NF)——消除传递依赖

  • 要求:表必须满足 2NF,且非主属性不能传递依赖于主键

在选课信息表中:

  1. “教室”依赖于“课程名”(课程名决定教室)。
  2. “课程名”又依赖于主键“(学号, 课程名)”。
  3. 因此,“教室”是通过“课程名”传递依赖于主键的,这会导致冗余:同一个课程的教室信息可能被重复存储。

3NF 转换:

进一步拆分表,消除传递依赖:

  1. 学生信息表:

    学号 学生姓名 学院
    1001 张三 计算机学院
    1002 李四 数学学院
  2. 选课信息表:

    学号 课程名
    1001 数据库
    1001 高数
    1002 高数
  3. 课程信息表:

    课程名 任课老师 教室
    数据库 王老师 A101
    高数 李老师 B202

3NF 解决了传递依赖问题,进一步减少了数据冗余。


BCNF(Boyce-Codd Normal Form)——更严格的第三范式

  • 要求:在每个函数依赖中,左边的属性必须是候选键

特殊情况:

3NF 中如果存在非主属性决定主属性的情况,就不满足 BCNF。

例如:如果选课表变成这样:

学号 课程名 任课老师
1001 数据库 王老师
1001 高数 李老师
1002 高数 李老师

这里存在:

  • 任课老师 → 课程名(任课老师决定课程名)。
  • 但是“任课老师”不是候选键,违背了 BCNF。

BCNF 转换:

将表拆分为:

  1. 学生选课表:

    学号 课程名
    1001 数据库
    1001 高数
    1002 高数
  2. 任课老师表:

    课程名 任课老师
    数据库 王老师
    高数 李老师

总结

范式 核心问题 解决方法
1NF 数据非原子化(多值或集合) 拆分成单一值的记录
2NF 存在部分函数依赖 拆分表,消除部分依赖
3NF 存在传递依赖 拆分表,消除传递依赖
BCNF 非候选键的属性决定其他属性 更严格地规范主键和依赖关系

你可能感兴趣的:(数据库,oracle,mysql)