
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检查选项-------------------------------------------------

-- 演示检查选项的第一个选项，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检查选项------------------------------------------------

-- 演示检查选项的第二个选项，local
#清理上面演示产生的基表数据
delete from student where id in(5,15,17,25);#再删一下上面添加的数据
-- 【第一种情况: 有检查选项的视图基于没有检查选项的视图创建】
#建一个stu_v_4视图，不添加检查选项
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和local总结------------------------------------------

/*cascade:当我们在操作视图的时候，会递归的去找当前视图所依赖的视图，如果当前视图后面定义了有with local check option这样的检查选项，
那么所依赖的视图都会默认被附加上这个检查选项，操作的数据只有满足这个视图和所依赖的视图条件，才会执行成功; 如果当前视图后面没有定义
with local check option这样的检查选项，那么操作的数据时，只需要检查是否满足所依赖的视图的条件，当所依赖的视图没有with local check option
这样的检查选项，那么我们在操作数据的时候，将不对没有检查选项的视图做检查

local: 当我们在操作视图的时候，会递归的去找当前视图所依赖的视图，如果当前视图以及依赖的视图后面定义了有with local check option这样的
检查选项，那么将会去判定我们所操作的数据是否满足这个视图的条件，当在递归的过程中找到某一个视图在定义的时候，没有增加with local check option
这样的检查选项，此时我们在操作数据的时候，将不对这个视图的条件做检查*/


-- -------------------------------------------------视图 更新及作用------------------------------------------------

#这节课是纯文本阅读，不需要解开注释运行

/*通过上节课视图检查选项的学习，我们知道当我们对视图中的数据进行插入、更新、删除时，那么检查选项会去检查我们所操作的数据是否符合
视图定义时的条件

思考: 对于MySQL的视图，是任何视图都能进行增删改吗，并不是这样的，这节课就来学习关于视图的更新需要什么样的条件，也就是说符合什
么样条件的视图才可以更新呢。如下

视图的更新
1. 要使视图可更新，视图中的行与基表(基础表)中的行之间必须存在一对一的关系。如果视图包含以下任何一项，则该视图不可更新
(1)聚合函数或窗口函数，如sum()、min()、max()、count()
(2)去重，例如distinct
(3)分组，例如group by
(4)过滤，例如having
(5)union 或者 union all

例如
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表时，只能看到的用户的基本手段，屏蔽手机号和邮箱两个字段
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;
#视图相当于封装查询语句，简化了操作，跟用函数一样

