触发器
trigger,在表的插入(insert),更新(update),删除(delete)操作发生时自动执行MySQL语句
创建触发器时需要给出的信息:
- 触发器名
- 在操作前还是操作后触发(before/after)
- 被什么操作触发(insert/update/delete)
- 关联的表
使用触发操作的数据:
- insert:可通过new访问被插入的行,before insert 可以更新new中的值(允许更改被插入的值)。
- update:old访问更新前的值,new访问更新后的值。
- update:可通过old访问被删除的行,old中的值是只读的。
sql
#创建触发器
create trigger 触发器名
before|after
update|insert|delete on 表名
for each row
begin
触发器逻辑;
end;
#删除触发器
drop trigger [if exists] 触发器名;
sql
#更新部门,对应部门的员工涨工资
drop trigger if exists mytrigger;
create trigger mytrigger after update on dept
for each row
begin
update emp
set sal = sal+100
where deptno = new.deptno;
end;
update dept
set loc = 'BEIJING'
where loc = 'DALLAS';
触发器练习
需求:给部门表添加员工数量字段,员工表添加员工时对应部门员工数量自动加1
- dept表添加一个字段:员工数量
- 部门表的员工数量更新为正确值
- 写一个触发器,当员工表添加员工时,对于部门员工数量加1
- 员工表添加员工测试
视图
view,由查询结果形成的一个虚拟的表。视图不能索引,也不能有关联的触发器。
sql
create view 视图名 as 查询语句;
#修改视图
alter view 视图名 as 查询语句;
#删除视图
drop view [if exists] 视图名;
#查看创建视图语句
show create view 视图名;
sql
#查询出员工的部门名称,员工的领导名和薪水等级
create view emp_all as
select e1.ename,e2.ename mgr_name,d.dname,s.grade
from emp e1
left join emp e2 on e1.mgr = e2.empno
join dept d on e1.deptno = d.deptno
join salgrade s on e1.sal between losal and hisal;
select * from emp_all;
视图的作用:
- 重用SQL语句
- 简化查询语句,隐藏复杂的SQL
- 安全:使用视图的用户只能访问他们被允许查询的结果集
视图的实现原理:
- 临时表算法:将视图的查询结果存放到临时表里,需要访问视图时,直接访问这个临时表,优点是可以处理复杂查询,缺点是引入了创建表的性能开销。
- 合并算法:重写含有视图的查询,将视图的定义sql直接合并到查询sql里,性能更高。
MySQL优化器根据查询的具体情况来选择哪种算法。如果视图中包含group by,distinct,聚合函数等,只要无法在原表记录和视图记录中建立一一映射的场景中。MySQL都将使用临时表算法来实现视图。
不同视图与原表的联系:
- 普通视图:通常不能直接更新,修改视图不会影响原表。
- 可更新视图:可以直接更新,修改视图影响原表。
- 物化视图:通常是只读的,修改视图不会影响原表。
注意:基于单表的视图,修改原表数据,可以通过维护视图完成视图的更新。
可更新视图:可以通过更新这个视图来更新视图涉及的相关表。只要指定了合适的条件,就可以更新,删除甚至是在相关表中插入数据。
sql
#查看合并算法
create view abc as select * from emp;
explain select * from abc;
#查看临时表算法
create view dept_emp as select * from emp group by deptno;
explain select * from dept_emp;
#修改可更新视图
insert into abc(empno) values(111);
update abc
set
empno = 222
where empno = 111;
insert into dept_emp(empno) values(111);
#不可更新视图
create view abc2 as select deptno from emp;
insert into abc2(deptno) values(111);#无主键,导致更新时主键为空报错
create view abc2 as select empno from emp;
insert into abc2(empno) values(111);#不报错
insert into abc2(empno) values(111);#报错,已经有主键值为111的记录第二次添加主键值为111会报错
create view abc2 as select deptno * 2 from emp;
update abc2
set
deptno = 222
where deptno in NULL;#不存在deptno字段,因为abc中的是deptno*2字段,所以无法修改,报错
三范式
范式是关系型数据库设计的一种规范,目标是消除冗余,建立结构合理的数据库,从而提升数据存储和使用的性能。
第一范式(1NF)
每列的原子性,表中的每一个字段都是不可分割的,同一列中不能有多个值。第一范式是对关系模式的基本要求,不满足第一范式的数据库不是关系型数据库。
- 不满足第一范式的示例:
|------|------|-------------------------|
| 学生编号 | 学生姓名 | 联系方式 |
| 1001 | 张三 | zs@163.com,135999999999 |
| 1002 | 李四 | ls@163.com,136889999999 |
| 1003 | 王五 | ww@163.com,125999999999 |
注意:第一范式要根据实际需求来定,联系方法中存在邮箱和电话,即不满足第一范式
第一范式怎么要求,举个例子,如果考虑地址字段(河南省郑州市高兴区知行街135号)是否符合第一范式,如果经常访问地址中的城市部分,这个字段就不符合第一范式,需要进行拆分,可以拆分成河南省,郑州市,高兴区知行街135号。如果经常访问整个地址,就符合第一范式,拆分反而不利于查询完整地址。
第二范式(2NF)
确保唯一性和依赖性,每个表都有主键,且其他字段完全依赖主键。
第二范式是在第一范式的基础上,要求表中的每一条数据可以被唯一区分,通常使用主键实现,其他所有字段都完全依赖主键。
其他字段依赖主键是指,其他每个字段都与主键完全相关,当确定主键的值时就能确定其他所有字段的值。也就是说一张表只能存一种数据,不可以吧多种数据存到一张表中,比如课程表的内容存到学生表中。
完全依赖是指,联合主键时,其他字段不可以只依赖主键中的某个字段,必须依赖联合主键中的每一个字段。
- 不满足第二范式的示例:
成绩表(score)
|------|-----|------|----|
| 学号 | 课程号 | 学生姓名 | 成绩 |
| 1001 | 001 | 张三 | 90 |
| 1002 | 002 | 李四 | 80 |
| 1001 | 001 | 张三 | 90 |
其中学生名只依赖学号,与本表中的联合主键(学号,课程号)产生了部分依赖,即只依赖学号,所以该表不满足第二范式。
第三范式(3NF)
在第二范式的基础上,非主键字段必须直接依赖于主键,不能存在传递依赖。
- 不满足第三范式的示例:
|-----|------|------|-------|
| 课程号 | 课程名 | 授课教师 | 教师办公室 |
| 001 | 线性代数 | 张三 | 302 |
| 002 | 概率论 | 李四 | 303 |
| 001 | 数理统计 | 王五 | 302 |
我们可以看到,整张表中不存在部分依赖,但是教师办公室依赖于授课教师,授课教师又依赖于课程号,形成了(课程号)->(授课教师)->(教师办公室)传递依赖,因此不满足第三范式。
范式总结
- 1NF:原子性,字段分割到不可分割。
- 2NF:唯一性和完全依赖,要有主键,且其他字段完全依赖于主键。
- 3NF:没有传递依赖。
范式的优缺点:
- 优点:
- 重复数据很少甚至没有。
- 冗余字段少,表更小,可以更好的放在内存里,执行操作时更快。
- 进行更新操作更快。
- 可以更少的使用group by 和 distinct。
- 缺点:进行复杂一点的查询需要关联,并且可能使索引无效。