当前位置: 首页 > news >正文

MySQL —— 表的设计

表的设计

在设计表之前,我们需要从需求中获得实体(实体就是一张张表),实体的属性就是表中的字段(列),然后确定实体与实体之间的关系,最后使用 SQL 语句去创建具体的表

在设计表的时候我们会遵守一些规则,这些规则叫做三大范式(范式是描述数据关系的模型),下面我们来了解一下三大范式。

第一范式

第一范式是关系型数据库的一个基本要求,如果不满足第一范式就不是关系型数据库。

第一范式要求表里的字段不能继续拆分

举个例子:
我们定义一个学生表,但是你只是给了一个字段——学生,可是这个学生范围很广泛,有学生的姓名,性别,年龄,班级,学号等等,说明学生这个字段是可以拆分的,所以你最开始定义的表是不符合第一范式的。

如果一张表里的所有的字段都无法拆分那就满足第一方式,还是学生表为例子:现在创建了学号,姓名,性别,年龄这四个字段组成学生表那就符合第一范式,因为每一个字段都是不可分的。

在定义表的时候,对照数据中的数据类型,将每一个字段都可以用一个数据类型表示,那么当前这个表就天然满足第一范式

第二范式

第二范式在满足第一范式的基础上,存在于复合主键的情况下,不存在非关键字段对任意候选键的部分函数依赖

简单来说,对于由两个或者多个关键字段(即复合主键)决定一条记录的情况的时候,如果一行数据中非主键的字段与复合主键的部分字段存在关系,就说明存在部分函数依赖,不满足第二范式

现在举个例子:
假设我有一张学生成绩表,表里有一下这些字段:
在这里插入图片描述

这张表设计是存在问题的,首先我们可以假设将学号设置为主键,然后通过学号我们是可以确定这个学生的姓名性别年龄以及班级的,但是再往后看,我们会发现通过课程名称我们应该是可以找到课程的学分,这时候这个课程的成绩到底是由什么决定的,那应该就是学生和课程共同决定的(学生参加这个课程的考试之后就会有成绩),那这时候我们就可以将学号和课程名称定义为复合主键,在这张表中姓名和课程学分就是非关键字段,但是却与候选键发生了函数依赖(也就是存在关系),那么就会违反第二范式。

以上面的学生成绩表为例:
将表进行拆分,学生表(学生学号,姓名,性别,年龄与班级),课程表(课程编号、名称,课程学分),还有一张课程成绩表(学号,课程编号,成绩)。

如果一张表没有复合主键,那么这张表一定满足第二范式。

如果不满足第二范式有什么后果?

  1. 造成数据冗余:就像上面的表,本来我需要查看的是学生考了多少分,但是你还告诉我学生的性别,年龄,班级甚至课程学分我都不想知道,这就是数据冗余,并且很浪费空间,应该让每一张表都有自己特定的数据进行保存,而不是全部塞进去
  2. 更新可能会出现异常:假设你要修改课程对应的学分,那你是不是要把每一个都有这个课程的数据行都要进行修改,不仅费时费力,万一数据库服务器突然坏了一秒钟,你之前更新的数据还不一定会保存下来。
  3. 插入异常,如果你要新增一门新课程,那你怎么往这张表插入数据,设计表的时候有些列不能为空的,那你是不是还要伪造哪些空数据,或者你等到有人考了这门成绩出来以后再加入数据库中(黄瓜菜都凉了)。
  4. 删除异常:假设所有参加 JavaEE 课程的同学都毕业了,但是JavaEE 的新学生还没这么快考试,那你如果删除这些毕业的人的数据的时候,也就连JavaEE 的课程信息也删除了。

如何避免第二范式:
在设计复合主键的时候,一定要考虑清楚其他字段会不会与复合存在部分函数联系。

第三范式

第三范式在第二范式的基础上,不存在非关键字段对任一候选键存在传递依赖。

以下面的学生表为例:
在这里插入图片描述

这张表主键定义为学号,但是我们可以 从学号得知学院名称 再得知学院的地址和电话,由于学院名称是非关键字段,所以存在了传递关系。

那该如何设计这张学生表?
设计成两张表,一个学院表(学院编号,学院名称,学院电话,学院地址)
一张学生表(学号,姓名,学院编号)设计成主外键键关系即可。

表的关系

一对一

举个例子:一个中国公民只有一个身份证

如何设计表:
创建两张表,分别记录中国公民的个人信息(姓名,电话,现居地址),身份证信息(身份证号,姓名,年龄,性别)
然后我们可以再公民表中设计一个外键(身份证号)。

create table idcard(id bigint primary key comment '身份证号',name varchar(20) not null comment '姓名',gender varchar(1) not null comment '性别',age int not null comment '年龄'
);create table person(id bigint primary key auto_increment comment '编号',name varchar(20) not null comment '姓名',address varchar(100) comment '现居地址',foreign key (id) references idcard(id)
);

一对多(多对一)

举例:一个班级存在很多个学生,这是一对多的关系
同理,很多个学生都在一个班级,这是多对一的关系

如何设计表:
还是一样,先创建不同的实体表,再去建立联系

演示:创建班级表(班级编号,班级人数)
再创建学生表(学生学号,姓名,年龄,所属班级)
最后确定关系,我们可以在学生表添加一个班级外键:

create table class(id bigint primary key comment '班级编号',num int comment '人数'
);create table student (id bigint primary key auto_increment comment '学生学号',name varchar(50) not null comment '姓名',age int comment '年龄',foreign key (id) references class(id)
);

多对多

举个例子:学生与课程的关系,一个学生可以选择很多个课程,一个课程同时也可以包含很多个学生。

如何设计?
首先分别创建好实体表,一张学生表(学生学号,姓名,年龄) 一张课程表(课程编号,课程名称,课程学分)
然后确定关系发现是多对多,那就再创建一张表——关系表(关系表自身的编号,学生学号,课程编号)

create table student (id bigint primary key auto_increment comment '学生学号',name varchar(50) not null comment '姓名',age int comment '年龄'
);create table course(id bigint primary key auto_increment comment '课程编号',name varchar(20) not null comment '课程名称',score decimal(2,1) comment '学分'
);create table student_course (id bigint primary key comment '自身编号',student_id bigint not null comment '学生学号',course_id bigint not null comment '课程编号',foreign key (student_id) references student(id),foreign key (course_id) references course(id)
);

我们还可以在这张关系表中添加一个成绩的字段。

没有关系

对于没有关系的表,我们直接设计即可,不需要考虑其与其他的关系(因为本来就没有关系)

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 简单聊一聊Vue是如何管理多环境的后端服务的?
  • leetcode787. K 站中转内最便宜的航班——优先队列优化的Dijkstra算法+剪枝
  • 【C#】计算多边形的面积
  • Redis的面试题
  • 数据类型练习
  • 25-原理图BOM的输出
  • 智慧宠物护理:智能听诊器引领健康监测新潮流
  • 利用 Docker 和 Poetry 优化 Python 应用部署
  • 鸿蒙(API 12 Beta3版)【时域可分层视频编码】 音视频编码
  • YOLOv8改进 | 主干网络 | 用EfficientNet卷积替换backbone【教程+代码 】
  • Python爬虫:下载4K壁纸
  • 六、go函数
  • 我与数据库的七年之痒:从初识到没它不行
  • Hive SQL ——窗口函数源码阅读
  • C++第一讲:开篇
  • [译] 理解数组在 PHP 内部的实现(给PHP开发者的PHP源码-第四部分)
  • 【许晓笛】 EOS 智能合约案例解析(3)
  • Akka系列(七):Actor持久化之Akka persistence
  • AngularJS指令开发(1)——参数详解
  • canvas 高仿 Apple Watch 表盘
  • CentOS7 安装JDK
  • express.js的介绍及使用
  • JavaScript/HTML5图表开发工具JavaScript Charts v3.19.6发布【附下载】
  • JavaScript设计模式之工厂模式
  • Java程序员幽默爆笑锦集
  • magento 货币换算
  • Meteor的表单提交:Form
  • Redis提升并发能力 | 从0开始构建SpringCloud微服务(2)
  • vue从创建到完整的饿了么(18)购物车详细信息的展示与删除
  • 从重复到重用
  • 我有几个粽子,和一个故事
  • 携程小程序初体验
  • 用element的upload组件实现多图片上传和压缩
  • 仓管云——企业云erp功能有哪些?
  • 长三角G60科创走廊智能驾驶产业联盟揭牌成立,近80家企业助力智能驾驶行业发展 ...
  • 积累各种好的链接
  • ​如何使用QGIS制作三维建筑
  • ‌‌雅诗兰黛、‌‌兰蔻等美妆大品牌的营销策略是什么?
  • # Swust 12th acm 邀请赛# [ A ] A+B problem [题解]
  • #!/usr/bin/python与#!/usr/bin/env python的区别
  • ###51单片机学习(2)-----如何通过C语言运用延时函数设计LED流水灯
  • #数学建模# 线性规划问题的Matlab求解
  • #我与Java虚拟机的故事#连载08:书读百遍其义自见
  • ( 10 )MySQL中的外键
  • (1)虚拟机的安装与使用,linux系统安装
  • (AngularJS)Angular 控制器之间通信初探
  • (pojstep1.3.1)1017(构造法模拟)
  • (免费领源码)Java#ssm#MySQL 创意商城03663-计算机毕业设计项目选题推荐
  • (算法)区间调度问题
  • (一)硬件制作--从零开始自制linux掌上电脑(F1C200S) <嵌入式项目>
  • (自用)gtest单元测试
  • .Net Core 微服务之Consul(三)-KV存储分布式锁
  • .NET Core 中的路径问题
  • .NET 材料检测系统崩溃分析
  • .Net6使用WebSocket与前端进行通信