create database if not exists bilibili; #创建数据库bilibili use bilibili; #选择bilibili数据库,即可进行下面的代码演示 drop database if exists bilibili; #代码演示结束后删除bilibili数据库。这个小文件全部代码演示完再删 show databases; #查看是否删除完成
#准备数据,新建一个学生表
create table student(
id int auto_increment primary key comment '主键ID',
name varchar(10) comment '姓名',
no varchar(10) comment '学号'
) comment '学生表';
insert into student values (null,'黛绮丝','2022567890'),(null,'谢逊','2022567891'),(null,'殷天正','2022567892'),(null,'韦一笑','2022567893');
-- 创建视图
create or replace view stu_v_1 as select id,name from student where id <= 10;
#执行上面那条语句之后,就会在tables同级目录下生成views目录
-- 查询视图
show create view stu_v_1;#查看创建视图语句
select * from stu_v_1;#查看视图数据
select * from stu_v_1 where id < 3;#查看视图数据
-- 修改视图 #(1)第一种写法
create or replace view stu_v_1 as select id,name,no from student where id <= 10;
#原来的stu_v_1视图只有id和name字段,我们现在新增一个字段no #(2)第二种写法
alter view stu_v_1 as select id,name from student where id <= 10;
##原来的stu_v_1视图只有id、name、no字段,我们现在把视图改为只有id、name字段
-- 删除视图
drop view if exists stu_v_1;
#先创建一个视图
create or replace view stu_v_1 as select id,name from student where id <= 20;
#查看视图数据
select * from stu_v_1;
#往视图里添加数据
insert into stu_v_1 values(6,'Tom');
#由于视图不存储数据,具体的数据是在基表(student)中存储,也就是我们上面那行的插入数据是插入到了student表
#查看视图数据,可以看到我们上面那行插入进去的数据
select * from stu_v_1;
#往视图再次插入数据
insert into stu_v_1 values(30,'Tom');
#查看视图数据,可以发现并不能查看到id为30的数据,id为30的数据被插入进基表,但是没有成功插入stu_v_1视图
select * from stu_v_1;
#如何解决数据插入进基表,但是没插入进stu_v_1视图的问题呢。解决:检查选项,如下
drop view if exists stu_v_1;#先删一下视图
delete from student where id in(6,30);#再删一下上面添加的id为6和id为30的数据
create or replace view stu_v_1 as select id,name from student where id <= 20 with cascaded check option;#重新建视图,加上检查选项
insert into stu_v_1 values(6,'Tom');#可以正常添加数据
insert into stu_v_1 values(30,'Tom');#添加数据报错,原因是插入的id值不在我们允许的范围内,检查选项维护了我们基表和对应视图的一致性
#cascaded check可以替换为local,效果是一样的
-- 演示检查选项的第一个选项,cascade,也就是级联,插入数据时不但会检查当前视图,还会检查当前视图依赖的视图
第一种情况: 有检查选项的视图基于没有检查选项的视图创建
drop view if exists stu_v_1;#先删一下视图
delete from student where id in(6,30,5,25);#再删一下上面添加的数据
#建一个stu_v_1视图,不添加检查选项
create or replace view stu_v_1 as select id,name from student where id <= 20;
#插入数据
insert into stu_v_1 values(5,'Tom');#数据正常插入
insert into stu_v_1 values(25,'Tom');#超出20,但是还是可以插入。原因:没有添加检查选项
#再建一个stu_v_2视图,并且关联stu_v_1视图,注意stu_v_2视图是添加了检查选项的
create or replace view stu_v_2 as select id,name from stu_v_1 where id >= 10 with cascaded check option;
#插入数据
insert into stu_v_2 values(7,'Tom');#由于7不满足>=10,所以这行插入报错
insert into stu_v_2 values(26,'Tom');#也插入报错。原因:由于stu_v_2视图是基于stu_v_1视图才创建的,所以就间接给没有检查选项的
#stu_v_1视图加上了检查选项,所以插入的数据不仅要满足stu_v_2的条件,还要同时满足stu_v_1的条件,数据才能插入成功
insert into stu_v_2 values(15,'Tom');#数据正常插入。原因:数据都满足了stu_v_1和stu_v_2视图的条件
第二种情况: 没有检查选项的视图基于有检查选项的视图创建
#创建一个stu_v_3视图,并且关联stu_v_2视图,注意stu_v_3视图是没有检查选项的,stu_v_2视图有检查选项
create or replace view stu_v_3 as select id,name from stu_v_2 where id <= 15;
#插入数据
insert into stu_v_3 values(11,'Tom');#可以,由于stu_v_3视图没有检查选项,所以就直接去检查stu_v_2视图,发现满足stu_v_2视图的条件,所以直接执行成功
insert into stu_v_3 values(17,'Tom');#可以,由于stu_v_3视图没有检查选项,所以就直接去检查stu_v_2视图,发现满足stu_v_2视图的条件,所以直接执行成功
insert into stu_v_3 values(28,'Tom');#报错,stu_v_3视图没有检查选项,stu_v_2视图检查选项符合,但是stu_v_2视图是基于stu_v_1视图创建的,所以还需要去检查stu_v_1的条件,28不符合stu_v_1的<=20,所以报错,数据不能插入
-- 演示检查选项的第二个选项,local #清理上面演示产生的基表数据
delete from student where id in(5,15,17,25);#再删一下上面添加的数据
第一种情况: 有检查选项的视图基于没有检查选项的视图创建
#建一个stu_v_4视图,不添加检查选项
xxxxxxxxxx
create or replace view stu_v_4 as select id,name from student where id <= 15;
#插入数据
insert into stu_v_4 values(5,'Tom');#可以
insert into stu_v_4 values(16,'Tom');#可以,原因:stu_v_4没有添加检查选项
#再建一个stu_v_5视图,并且关联stu_v_4视图,注意stu_v_5视图是添加了检查选项的
create or replace view stu_v_5 as select id,name from stu_v_4 where id >= 10 with local check option;
#插入数据
insert into stu_v_5 values(13,'Tom');#可以,原因:满足stu_v_5的检查选项条件,所以直接执行成功
insert into stu_v_5 values(17,'Tom');#可以,原因:由于stu_v_5视图是基于stu_v_4视图才创建的,但是stu_v_4没有添加检查权限,所以不需要
#去检查是否符合stu_v_4的检查权限,只检查是否符合stu_v_5的检查权限,符合就执行成功。注意这一点是local和cascade不同的地方
第二种情况: 没有检查选项的视图基于有检查选项的视图创建
#创建一个stu_v_6视图,并且关联stu_v_5视图,注意stu_v_6视图是没有检查选项的,stu_v_5视图有检查选项
create or replace view stu_v_6 as select id,name from stu_v_5 where id < 20;
#插入数据
insert into stu_v_6 values(14,'Tom');#可以,由于stu_v_6视图没有添加检查选项条件并且stu_v_6依赖于stu_v_5,所以就直接去判断符不符
#合stu_v_5的检查选项条件,满足就执行成功
第三种情况: 有检查选项的视图基于有检查选项的视图创建
#创建一个stu_v_7视图,并且关联stu_v_5视图,注意stu_v_7视图是有检查选项的,stu_v_5视图有检查选项
create or replace view stu_v_7 as select id,name from stu_v_5 where id < 13 with local check option;
#插入数据
insert into stu_v_7 values(12,'Tom');#可以,同时符合stu_v_7、stu_v_5视图的查询条件
cascade:当我们在操作视图的时候,会递归的去找当前视图所依赖的视图,如果当前视图后面定义了有with local check option这样的检查选项, 那么所依赖的视图都会默认被附加上这个检查选项,操作的数据只有满足这个视图和所依赖的视图条件,才会执行成功; 如果当前视图后面没有定义 with local check option这样的检查选项,那么操作的数据时,只需要检查是否满足所依赖的视图的条件,当所依赖的视图没有with local check option 这样的检查选项,那么我们在操作数据的时候,将不对没有检查选项的视图做检查
local: 当我们在操作视图的时候,会递归的去找当前视图所依赖的视图,如果当前视图以及依赖的视图后面定义了有with local check option这样的 检查选项,那么将会去判定我们所操作的数据是否满足这个视图的条件,当在递归的过程中找到某一个视图在定义的时候,没有增加with local check option 这样的检查选项,此时我们在操作数据的时候,将不对这个视图的条件做检查
通过上节课视图检查选项的学习,我们知道当我们对视图中的数据进行插入、更新、删除时,那么检查选项会去检查我们所操作的数据是否符合 视图定义时的条件
思考: 对于MySQL的视图,是任何视图都能进行增删改吗,并不是这样的,这节课就来学习关于视图的更新需要什么样的条件,也就是说符合什 么样条件的视图才可以更新呢。如下
视图的更新
要使视图可更新,视图中的行与基表(基础表)中的行之间必须存在一对一的关系。如果视图包含以下任何一项,则该视图不可更新 (1)聚合函数或窗口函数,如sum()、min()、max()、count() (2)去重,例如distinct (3)分组,例如group by (4)过滤,例如having (5)union 或者 union all
例如
xxxxxxxxxx
create view stu_v_count as select count(*) from student;
insert into stu_v_count values(10);#报错
原则:视图中的数据必须对应基表中的一行数据
视图的作用
1、简单。视图不仅可以简化用户对数据的理解,也可以简化他们的操作。那些被经常使用的查询可以被定义为视图,从而使得用户不必为以后的操作 每次指定全部的条件。也就是在业务中,一些复杂的查询条件,我们不用每次在业务开发中把这些复杂的条件一条一条的写出来,我们可以把复杂的 条件定义在一个视图当中,在业务操作的时候,只需要针对视图进行操作就可以了
2、安全。数据库可以授权,但是MySQL的授权只能控制到表,如果我们需要控制表中的字段,MySQL的授权是做不到的,此时就需要使用视图。 通过视图,用户只能查询和修改他们所能见到的数据。例如只想让用户看到学生表的id和姓名,不想让用户看到学号,此时就可以创建一个视图,视图 对应的select语句就是只查询id和姓名。保证了敏感数据的安全性
3、数据独立。视图可帮助用户屏蔽真实表结构带来的影响。例如我们基础表的某个字段名发生了变化,此时就去更新视图的语句上把新的字段名写上去, 给这个新的字段名取一个原来字段别名,就可以让用户不察觉到我们的字段名变化。例如我们把基础表的name字段改为了studentname,那我们只需要在 更新视图语句下做如下操作,即可让用户不察觉到我们的字段名变化 原来的更新视图语句:create or replace view stu_v_1 as select id,name from student where id <= 15 with local check option; 修改后的更新视图语句:create or replace view stu_v_1 as select id,studentname as name from student where id <= 15 with local check option;
#根据如下需求,定义视图
1、为了保证数据库表的安全性,开发人员在操作tb_user表时,只能看到的用户的基本手段,屏蔽手机号和邮箱两个字段
xxxxxxxxxx
create view tb_user_view as select id,name,profession,age,gender,status,createtime from tb_user;
select * from tb_user_view;#验证
2、查询每个学生所选修的课程(三张表联查),这个功能在很多的业务中都有使用到,为了简化操作,定义一个视图
准备数据,我们在上面的学习已经创建过课程表和学生表,此时我们还需要一张中间表,如下
create table student_course( #学生表和课程表的中间表
id int auto_increment comment '主键' primary key,
studentid int not null comment '学生ID',
courseid int not null comment '课程ID',
constraint fk_courseid foreign key (courseid) references course (id),
constraint fk_studentid foreign key (studentid) references student (id)
) comment '学生课程中间表';
insert into student_course values (null,1,1),(null,1,2),(null,1,3),(null,2,2),(null,3,1),(null,4,4);
#创建视图tb_stu_course_view
select s.name as student_name,s.no as student_no,c.name as course_name from student as s,student_course as sc,course c where s.id = sc.studentid and sc.courseid = c.id;
create view tb_stu_course_view as select s.name as student_name,s.no as student_no,c.name as course_name from student as s,student_course as sc,course c where s.id = sc.studentid and sc.courseid = c.id;
#优点:后续不需要每次都写这条多表联查的SQL,我们只需要查看视图就可以了,如下
select * from tb_stu_course_view;
#视图相当于封装查询语句,简化了操作,跟用函数一样