1.数据库的三范式
使用范式的根本目的是:减少数据冗余,尽量让每个数据只出现一次,获取数据时通过 join 拼接出最后的数据。
一范式(1NF):域应该是原子性的,即数据库表的每一列都是不可分割的原子数据项。第一条范式好理解,属性不可拆分。
二范式(2NF)是建立在一范式的基础上的。概念是每个非主属性都完全函数依赖于主码。 只要数据列中出现数据重复,就要把表拆分开来。
看图:
可以用模式分解的办法将非2NF的关系模式分解为多个2NF的关系模式。去除部分函数依赖关系的方法为:
- 用组成主码的属性的集合的每一个子集作为主码构成一个关系模式
- 将依赖于这些主码的属性放入对应的关系模式
- 最后去掉只有主码的子集构成的关系模式
比如现在有一个关系模式SLC(Sno,Sname,Ssex,Sdept,Sloc,Cno,Grade)
(Sno,Cno)是主码,Sname依赖于Sno, 所以存在非主码属性对主码的部分函数依赖。
所以第一步拆出来主码为(Sno,Cno),(Cno), (Sno)
第二步将属性填进去(Sno,Sname,Ssex,Sdept,Sloc) ,(Cno),(Sno,Cno,Grade)
第三步去掉只有主码的子集构成的关系模式(Cno),然后一个关系模式就拆成了两个关系模式,拆完之后对剩下的两个关系模式在分析看看存不存在部分函数依赖的关系。
第二范式就是拆表,拆表首先要找到表的码,即不同的信息。根据表的码可以拆成两个表。
三范式(3NF)是建立在二范式的基础上的。概念是:所有的非主属性都不传递依赖于主码。一个数据表中不能包含已经在别的表中的非关键信息,属性不依赖其他非主属性。就是说,说,一张表中的所有属性,都由它的码直接决定,不能依靠其他的中间属性,如果有这样的中间属性,那就应该拆分成新的表。要求:表中的每一列都要与主键直接相关,而不是间接相关。
语义为每个系都分配一栋宿舍楼,那么,这个关系模式(Sno ,Sname,Ssex,Sdept,Sloc) 就存在传递依赖,存在传递依赖照样会出现数据冗余的现象。Sno->Sdept, Sdept->Sloc 。所以可以按以下方法消除传递依赖
第一步对于不是候选码的因子删去他的依赖属性Sno ,Sname,Ssex,Sdept),第二步新建关系模式(Sdept,Sloc),将属性依赖添加进行。第三步将决定因子作为新关系模式的主码。
注意事项:
1.第二范式与第三范式的本质区别:在于有没有分出两张表。
第二范式是说一张表中包含了多种不同实体的属性,那么必须要分成多张表,第三范式是要求已经分好了多张表的话,一张表中只能有另一张标的ID,而不能有其他任何信息,(其他任何信息,一律用主键在另一张表中查询)。
2.必须先满足第一范式才能满足第二范式,必须同时满足第一第二范式才能满足第三范式。
三大范式只是一般设计数据库的基本理念,可以建立冗余较小、结构合理的数据库。如果有特殊情况,当然要特殊对待,数据库设计最重要的是看需求跟性能,需求>性能>表结构。所以不能一味的去追求范式建立数据库。
由于数据库表结构的设计遵循第三范式,所以在大多数情况下我们需要从多张表关联查询数据。
2.分组计算和Group By
- 分组函数
分组函数的语法:
1.分组函数
‘’
还需要注意的是分组函数不能出现在where条件后面,必须将where换成having才行
2.COUNT
count(1)和count(*)是一样的,但是count(column1),如果column1为null,则不计数。
用子查询。group by 可以起到distinct相同的效果。
3.group by
我们可以按照一个字段进行分组,也可以按照多个字段组合进行分组,这样可以增加计算的维度,比如我要统计部门下面工作的薪水总和:
需要特别注意的是除了分组函数比如这里的SUM()以外的字段,都需要写在group by之后。
3.子查询
需要注意的是如果子查询的结果是一个元素那么可以使用 > ,=这些符号,但是如果子查询的结果是一个集合,那就要用IN了。
4.DML语句
- 插入数据
从一个表中copy一行
使用子查询作为插入目标
- 更新数据
采用子查询更新自己的表
- MERGE语句 :比较整合语句