文章目录
- 视图
- 视图的概念
- 视图的语法
- 创建视图
- 查看视图
- 修改视图
- 删除视图
- 基表与视图
- 检查选项
- CASCADED(级联式检查)
- LOCAL(本地式检查)
视图
视图的概念
视图是一个虚拟的表,它的内容是由查询语句动态生成的。视图本身并不存储数据,而是存储了一个查询语句,当用户查询视图时,数据库会执行这个查询语句,并返回结果。 简单来说,视图将查询语句打包,后续如果需要,直接查看视图(动态查询)即可。
视图的作用及优点:
-
简化查询
视图可以将一些复杂且常用的查询SQL打包起来,通过简单的查看视图操作即可访问数据,减少了重复的SQL编写。
-
保证数据安全
为视图授权而非表,通过创建视图的方式可以限制用户只能看到他们有权访问的数据,将让用户只能访问该视图,进而增强数据的安全性和保密性。
-
逻辑数据独立
视图可以隐藏基表的结构变化,当基表的结构改变时,只需要更新视图的定义,而不需要改变应用程序中的查询代码。
-
便于数据共享
视图可以作为数据共享的一种途径,不同用户可以根据自己的需要使用相同的视图。
-
增强可读性
可以重命名视图的列名,增强可读性
对于上述优点,可以在下面的介绍中慢慢体会。
视图的语法
创建视图
SQL语法如下:
CREATE [OR REPLACE] VIEW view_name [(column_list)] AS select_statement;
OR REPLACE
是可选项,用于在已经存在同名视图的情况下替换现有视图。如果不使用该可选项并且试图创建一个已存在的视图(视图名重复),MySQL会抛出一个错误。(column_list)
是一个可选项,用于显式指定视图的列名。如果指定了视图列名,则列的顺序和数量必须与查询语句返回的列相匹配。视图默认列名是查询语句中的列名。select_statement
就是一个SELECT
语句,用于定义视图的内容。该查询语句可以是任何合法的SELECT
语句,例如子查询、连接等(不过,如果包含一些子查询等会有一些注意事项,后面介绍)。- 视图可以基于另一个视图创建。
- 创建视图时尽量手动指定视图列名,避免列名重复的报错
- 视图本身并不存储任何数据,因此不能为视图创建索引。
SQL演示:
# 创建视图 v_student_1
CREATE VIEW v_student_1 (学号,姓名) AS SELECT sn,name FROM student WHERE class_id = 1; # 创建视图 v_student_score_class
CREATE VIEW v_student_score_class (学号,姓名,课程名,分数) AS
SELECT st.sn,st.name,co.name,sc.score
FROM student st,score sc,course co
WHERE st.student_id = sc.student_id
AND sc.course_id = co.course_id;
以上SQL就成功创建了两个视图,注意观察其中的语法。
查看视图
查看所有视图,它们包含在数据表列表中
SHOW TABLES;
演示:
查看视图的定义语句
SHOW CREATE VIEW view_name;
演示:
查询视图
SELECT [* | column_list] FROM view_name...;
- 可以把视图看作是普通的表,可以在视图的基础上进行复杂查询,包括与基表进行连接查询。
- 在指定要查询的视图的列时要与视图的实际列名匹配而非基表。
演示:
修改视图
修改视图定义
# 替换
CREATE OR REPLACE VIEW view_name [(column_list)] AS select_statement;# 修改
ALTER VIEW view_name [(column_list)] AS select_statement;
演示:
删除视图
SQL语法:
DROP VIEW [IF EXISTS] view_name;
演示:
基表与视图
这里主要讨论视图和基表的修改操作对彼此的影响。(这里的修改指的是插入和更新,删除操作直接且一致)
基表的修改操作会对视图产生影响,因为视图是基于基表的数据生成的,但是视图的修改操作对基表的影响就要讨论了。
对视图的更新和插入考虑:
- 满足基表约束的操作才能执行(此处外键约束可能会影响删除)
- 检查选项检查通过的操作才能执行
- 定义时的
SELECT
语句出现以下情况的视图(即不可更新视图)不允许更新/删除:- 使用聚合函数
- 使用
DISTINCT
- 使用
ORDER BY
子句 - 使用
GROUP BY
或HAVING
子句 - 使用
UNION
或UNION ALL
- 子查询
- 引用不可更新视图
- 某些多表查询
- 包含表达式或计算列
补充一点:如果基表结构发生了变化(表结构的变更,如增加/删除字段),而视图没有做出改变,可能会导致视图失效。所以当修改了基表结构时,需要重新定义视图。
检查选项
视图的检查选项(Check Option)用于确保通过视图插入或更新的数据符合视图定义中的条件。这有助于维护数据的一致性和完整性。MySQL 支持两种检查选项:LOCAL
(本地式检查) 和 CASCADED
(级联式检查)。没有设置检查选项的视图不会对插入/更新的数据进行检查。
适用场景:
- 多级视图:一个视图基于另一个视图创建,形成了多级视图结构。
- 过滤条件的视图:视图定义中包含
WHERE
子句,用于过滤基表中的数据。
【设置检查选项】
-- 创建或替换时
CREATE [OR REPLACE] VIEW view_name [(column_list)] AS select_statement [WITH [CASCADED|LOCAL] CHECK OPTION];-- 修改时
CREATE OR REPLACE VIEW view_name [(column_list)] AS select_statement [WITH [CASCADED|LOCAL] CHECK OPTION];
ALTER VIEW view_name [(column_list)] AS select_statement [WITH [CASCADED|LOCAL] CHECK OPTION];
了解了检查选项的设置,接下来先讨论一下检查选项的使用场景:
这是基表:
执行以下SQL并观察结果:
# 1.创建视图,注意WHERE条件
CREATE VIEW v_exam_1 AS SELECT * FROM exam WHERE chinese > 80;# 2.向视图中添加数据
INSERT INTO v_exam_1 VALUES(8,'测试用户',60,60,60);# 3.查询视图,发现插入的数据不在视图中,因为新数据的chinese字段的值 < 80
SELECT * FROM v_exam_1;
- 为了解决通过视图插入数据但视图查询不到的问题,引入了检查选项。
CASCADED(级联式检查)
启用CASCADED
检查选项后,MySQL会检查当前视图及其所有依赖视图的条件,即在插入或更新数据时,不仅会检查当前视图的条件,还会检查所有依赖视图的条件。
【演示】
# 视图1
CREATE VIEW v_exam_1 AS SELECT * FROM exam WHERE chinese > 80;# 基于视图1创建的视图2并且设置级联式检查选项
CREATE VIEW v_exam_2 AS SELECT * FROM v_exam_1 WHERE math < 90 WITH CASCADED CHECK OPTION;
- 描述:
- 视图1定义时没有设置任何检查选项
- 视图2基于视图1创建
- 视图2设置了级联式
CASCADED
检查选项
插入几条数据:
-- 通过视图2插入
# 既满足视图2的条件也满足视图1的条件
INSERT INTO v_exam_2 VALUES(9,'测试用户',88,88,88); -- 成功
# 只满足视图1的条件
INSERT INTO v_exam_2 VALUES(10,'测试用户',88,99,88); -- 失败
# 只满足视图2的条件
INSERT INTO v_exam_2 VALUES(11,'测试用户',77,88,88); -- 失败
# 不满足任何条件
INSERT INTO v_exam_2 VALUES(12,'测试用户',77,99,88); -- 失败-- 通过视图1插入
INSERT INTO v_exam_1 VALUES(13,'测试用户',77,88,88); -- 成功
- 视图2设置了级联式检查选项,当通过视图2插入(或更新)数据时,MySQL会检查插入(或更新)的数据是否满足视图2以及视图2关联的下级视图(即视图2基于哪些表创建)——视图1的
WHERE
条件,只要有一个不满足就不允许插入(或更新)。(不论下级视图是否有自己的检查选项) - 但是当通过视图1插入(更新)数据时,由于视图1没有检查选项,故不会进行任何检查。
LOCAL(本地式检查)
启动LOCAL
检查选项后,MySQL只检查当前视图的条件,即在插入或更新数据时,只会检查当前视图的条件,而不会检查依赖视图的条件。
【演示】
# 视图3
CREATE VIEW v_exam_3 AS SELECT * FROM exam WHERE chinese > 70;# 基于视图3创建的视图4并且设置本地式检查选项
CREATE VIEW v_exam_4 AS SELECT * FROM v_exam_3 WHERE english < 90 WITH LOCAL CHECK OPTION;
- 描述:
- 视图3定义时没有设置任何检查选项
- 视图4基于视图1创建
- 视图4设置了级联式
LOCAL
检查选项
插入几条数据:
-- 通过视图4插入
# 既满足视图4的条件也满足视图3的条件
INSERT INTO v_exam_4 VALUES(14,'测试用户',88,88,88); -- 成功
# 只满足视图3的条件
INSERT INTO v_exam_4 VALUES(15,'测试用户',88,88,99); -- 失败
# 只满足视图4的条件
INSERT INTO v_exam_4 VALUES(16,'测试用户',66,88,88); -- 成功
# 不满足任何条件
INSERT INTO v_exam_4 VALUES(17,'测试用户',66,88,99); -- 失败-- 通过视图3插入
INSERT INTO v_exam_3 VALUES(18,'测试用户',88,88,88); -- 成功
- 视图4设置了本地式检查选项,当通过视图4插入(或更新)数据时,MySQL会检查插入(或更新)的数据是否满足视图4的条件,同时判断与之关联的下级视图——视图3是否设置了检查选项,如果有则检查视图3的条件,如果没有则不进行条件的检查,只要有条件检查不满足则不允许插入(或更新)。
- 通过视图3插入(更新)数据时,由于视图3没有检查选项,故不会进行任何检查。
总结:
级联式(
CASCADED
): 当通过 设置了级联式检查的视图 插入/更新数据时,MySQL会检查该视图的WHERE
条件,同时检查与该视图关联的下级视图的WHERE
条件,即使下级视图没有设置检查选项,也会进行WHERE
条件的检查,最后只要有条件检查不满足就不允许插入/更新。(无中生有)本地式(
LOCAL
): 当通过 设置了本地式检查的视图 插入/更新数据时,MySQL会首先检查该视图的WHERE
条件,然后判断与之关联的下级视图是否设置了检查选项:如果设置了检查选项就会进行WHERE
条件检查,如果没有设置检查选项则不会进行WHERE
条件检查,最后只要有条件检查不满足就不允许插入/更新。(不会无中生有)
疑问:能直接向基表插入/更新数据,为什么还要通过视图插入/更新数据,这样做有哪些优势?
- 数据封装:视图可以封装复杂的逻辑和计算,使得插入或更新操作更加简洁。
- 数据验证:视图可以定义为只允许插入或更新符合特定条件的数据。
- 权限控制:通过视图可以更精细地控制用户对数据的访问权限。可以授予用户对视图的插入或更新权限,而不必授予对基表的直接访问权限,从而提高安全性。
- 简化开发:开发时可以通过视图进行数据操作,而不需要直接处理复杂的SQL语句。
完