在这里我们讲解一下三个范式的原理和作用:
当谈论关系型数据库设计时,"范式"指的是数据库表的结构设计规范。下面是对三个主要范式的通俗易懂的解释:
第一范式(1NF):确保每个列都是原子的 第一范式要求数据库表中的每个列(字段)都只包含最基本的数据,而不包含多个值。如果一个列中包含了多个值,就需要将其分解成多个独立的列。换句话说,第一范式确保每个列都是原子的。
例如,如果有一个包含“姓名”和“电话号码”两个列的表,如果存在一个人有多个电话号码,将其拆分成多个行,每个行只包含一个电话号码。
第二范式(2NF):确保非键属性完全依赖于全部键 第二范式要求数据库表中的每个非键属性都完全依赖于表的全部键,而不是只依赖于部分键。如果某个非键属性只依赖于部分键,那么应该将其分解到一个新的表中。
例如,如果有一个包含“订单号”(键)、“产品号”(键)和“产品名称”的表,如果存在一个产品名称只与订单号有关,那么应该将“产品名称”独立成一个表,并通过订单号来关联。
第三范式(3NF):确保非键属性不相互依赖 第三范式要求数据库表中的每个非键属性都不相互依赖。换句话说,不允许一个非键属性依赖于另一个非键属性。如果出现这种情况,应该将其提取到一个独立的表中。
例如,如果有一个包含“学号”(键)、“课程号”(键)和“学生姓名”的表,如果存在一个课程号只与学生姓名有关,那么应该将“学生姓名”独立成一个表,并通过学号来关联。
这些范式的作用是确保数据库表的结构合理、无冗余、易于维护和扩展。通过遵循范式,可以尽可能地减少数据冗余,提高数据的一致性和完整性,同时也能使数据库的设计更加规范和易于理解。然而,需要根据具体的业务需求和性能考虑,灵活应用范式规范。
多表查询
目录
多表查询必要条件:主外键相等
在我们这里就是
SELECT * FROM student,grade WHERE student.studentid = grade.studentid;
通过主外键进行条件过滤,得到有意义的行
多表查询中,我们不要做无意义的操作,不要去把没用的东西也找出来
例如:下面按升级的顺序让我们来理解一下
-
首先,把两张表拼在一起(但这是笛卡尔积的形式形成新的结果)
-
其次,
SELECT * FROM student,grade;
这就相当于把两张表用笛卡尔积的形式结合在了一起 -
然后,
SELECT student.studentid,sname,courseid,score,grade.createtime FROM student,grade WHERE student.studentid=grade.studentid;
通过主外键相等进行条件过滤,筛掉无用的笛卡尔积结果,我们只需要正确匹配的结果
-
同时,我们不需要所有的信息都显示出来,这也是没有意义的,反而会影响我们观察数据,所以我们直接从结果中选出自己想要的列 值的注意的是我们需要区分两张表中相同的列,否则会报错
SELECT student.studentid,sname,courseid,score,grade.createtime FROM student,grade WHERE student.studentid = grade.studentid [AND student.studentid = 'WN005'] [AND score < 60 ORDER BY score DESC];
[] 中的内容可选,自己看情况写
这张图是对应 AND student.studentid = 'WN005'
这个条件的
这张图是对应 AND score < 60 ORDER BY score DESC
这个条件的
-
我们也可以选出平均值之类的数据
SELECT courseid,AVG(score) from student,grade WHERE student.studentid = grade.studentid GROUP BY courseid;
记住,我们只需要把SELECT courseid,AVG(score) from student,grade WHERE student.studentid = grade.studentid
这一部分内容的结果看做一张临时表就好,然后后面的语句的就是对单表的操作了
-
对表进行重命名(非必要,仅建议),以便于简化SQL语句。同时,在选择列时,也建议明确指定表名。
SELECT s.studentid,s.name,g.courseid,g.score,g.createtime FROM student s,grade g WHERE s.studentid = g.studentid;
在FROM student s,grade g
在FROM的时候对表名重新命名
多表连接方式
-
FROM AA,BB,CC
-
JOIN ... ON
SELECT * FROM student JOIN grade ON student.studentid = grade.studentid WHERE courseid='C01';
注意:这里只有 student.studentid = grade.studentid
这个连接条件放在 ON 后面,其他的查询条件都还放在WHERE 后面
内连接
以上的连接方式统称为 内连接
-
如果是三张表该怎么做?
-
比如查找成绩最差的学生的班主任是谁
-
第一步:先从成绩表中找到成绩最差的这个人的学号(也可用姓名)
SELECT studentid FROM grade WHERE ORDER BY score LIMIT 1;
-
第二步:用这个人的学号也可用姓名)去学生表中找到对应的班级编号
SELECT classid FROM student WHERE studentid = (SELECT studentid FROM grade WHERE ORDER BY score LIMIT 1);
-
第三步:通过对应的班级编号找到对应班级的班主任
SELECT teacher FROM class WHERE classid = (SELECT classid FROM student WHERE studentid = (SELECT studentid FROM grade WHERE ORDER BY score LIMIT 1));
-
-
上面的方法固然可以解决问题,但未免太过嵌套导致不易分析,我们建议使用多表查询的方法
SELECT s.name,c.teacher,g.score FROM student s,grade g,class c WHERE s.studentid = g.studentid AND s.classid = c.classid ORDER BY score LIMIT 1;
让我们来分析一下这段查询语句
-
三表查询,通过主外键相连的关系解决这个问题,student表中的studentid作为grade的外键,外键实际上为grade.studentid , student中的classid作为 classid表中的外键,外键实际上为为class.classid
-
因此,我们需要让两对主外键相等,即
s.studentid = g.studentid AND s.classid = c.classid
-
然后通过升序查询成绩表中的最小score来确定student表中的name(或studentid)从而达到锁定班级和班主任的目的
我需要找到s.name,c.teacher,g.score这三项,从student s,grade g,class c这三张表中去找
又因为student表中的studentid和grade表中的studentid分别作为主外键关联,student表中的classid和class表中的classid分别作为主外键相关联,于是需要s.studentid = g.studentid AND s.classid = c.classid这个条件
与此同时,我们需要对查询到的成绩score进行升序排列并找到最上面的值(也就是最小的)
此时就匹配到了我们想要的结果s.name,c.teacher,g.score这三项
表中无主外键,键在心中
在进行多表连接查询时,必须指定连接条件(通常是主外键关系),但是主外键关系没有明确在表中建立,也可以使用(毕竟只是查询,并没有做出什么增删改)
不过这样确实容易产生脏数据
无论哪个数据库,要维持主外键约束,是有性能开销的。因为要删除和修改时,要扫描一遍外表,看看能不能删除和修改
因此,有些情况下就会选择不在数据库层面建立主外约束,而在程序设计中设置主外键约束