【MySQL | 第八篇】MySQL 视图

前言:

视图(View)是一种虚拟存在的表。视图中的数据并不在数据库中实际存在,行和列数据来自定义视图的查询中使用的表,并且是在使用视图时动态生成的。

通俗的讲,视图只保存了查询的SQL逻辑,不保存查询结果。所以我们在创建视图的时候,主要的工作就落在创建这条SQL查询语句上。

一、视图是什么

视图是一种虚拟存在的表。视图中的行和列来自创建视图时使用的查询语句,真正的数据仍然在基础表中。

比如我们经常只想查看 id 小于等于 10 的用户,并且只需要 id 和 name 两个字段,就可以把这条查询封装成一个视图:

sql 复制代码
create or replace view stu_v_1 as
select id, name
from user
where id <= 10;

这条语句的含义是:创建一个名为 stu_v_1 的视图,它的数据来源是 user 表中 id 小于等于 10 的记录,并且只暴露 id、name 两列。

创建完成后,查询视图就像查询普通表一样:

sql 复制代码
select * from stu_v_1;

这句 SQL 查询的是视图,但底层数据仍然来自 user 表。视图只是把原本需要重复写的查询条件保存了下来。

二、视图的基本操作

创建视图的常用语法如下:

sql 复制代码
create [or replace] view 视图名称(列名列表) as
select 语句
[with [cascaded | local] check option];

其中 or replace 表示如果视图已经存在,就替换原来的定义;列名列表可以省略,省略时会使用 select 结果中的列名。

查看视图的创建语句:

sql 复制代码
show create view stu_v_1;

修改视图有两种常见写法。第一种是重新创建或替换:

sql 复制代码
create or replace view stu_v_1 as
select id, name, username
from emp
where id <= 10;

第二种是使用 alter view:

sql 复制代码
alter view stu_v_1 as
select id, name
from emp
where id <= 10;

删除视图时可以加 if exists,避免视图不存在时报错:

sql 复制代码
drop view if exists stu_v_1;

这些语句对应的操作很直接:创建视图、查看定义、调整视图查询逻辑、删除视图对象。删除视图不会删除基础表中的数据,因为真实数据并不存储在视图里。

三、用视图简化重复查询

视图最常见的用途就是简化查询。

假设系统里经常需要查询员工表中 id 小于等于 10 的员工,并且只展示 id 和 name:

sql 复制代码
create or replace view stu_v_1 as
select emp.id, emp.name
from emp
where id <= 10;

以后再查这部分数据时,不需要每次都写完整条件:

sql 复制代码
select * from stu_v_1;

这样做的好处不是让 SQL 神秘地变快,而是把常用查询逻辑固定下来。特别是查询条件比较多、字段比较多时,视图可以让上层使用者只关心"我要查哪个结果集",不用每次都关心底层表怎么筛选。

四、with check option 控制写入边界

视图不仅可以查询,有些简单视图也可以执行插入或更新。需要注意的是,通过视图修改数据时,真正改变的是基础表。

如果希望通过视图写入的数据仍然满足视图定义中的条件,可以加 with check option。

sql 复制代码
create or replace view stu_v_1 as
select id, name
from user
where id <= 10
with check option;

这个视图只允许看到 id 小于等于 10 的数据。加上检查选项后,通过这个视图插入或更新数据时,也必须满足 id 小于等于 10 这个条件。

下面这条语句满足条件,可以作为允许写入的例子:

sql 复制代码
insert into stu_v_1 values (2, 'zhangsan');

下面这条语句不满足条件:

sql 复制代码
insert into stu_v_1 values (11, 'lisi');

原因是 id 等于 11 的记录不属于这个视图能看到的范围。MySQL 8.0 官方文档对这个子句的说明也是这个意思:它会阻止插入或更新不满足视图查询条件的行。

这里要把重点放在"插入或更新"上。删除数据本身不产生一条新的行,所以 check option 的核心作用不是限制删除,而是防止通过视图写入一条视图自己都看不到的数据。

五、cascaded 和 local 的区别

视图还可以基于另一个视图继续创建。这个时候,检查选项就会出现两个范围:cascaded 和 local。

MySQL 中如果只写 with check option,不指定范围,默认行为是 cascaded。

先看 cascaded:

sql 复制代码
create or replace view v1 as
select id, name
from student
where id <= 20;

create or replace view v2 as
select id, name
from v1
where id > 10
with cascaded check option;

v2 依赖 v1。通过 v2 插入或更新数据时,不仅要满足 v2 自己的条件 id 大于 10,还要递归检查底层视图 v1 的条件 id 小于等于 20。

也就是说,能通过 v2 写入的数据范围应当同时满足:

sql 复制代码
id > 10 and id <= 20

再看 local:

sql 复制代码
create or replace view v4 as
select id, name
from student
where id <= 20;

create or replace view v5 as
select id, name
from v4
where id > 10
with local check option;

local 会检查当前视图的条件,并递归检查底层那些自己也声明了检查选项的视图。上面 v4 没有声明检查选项,所以通过 v5 写入时,重点检查的是 v5 的 id 大于 10。

可以把两者的区别记成一句话:cascaded 会把底层视图条件也一起纳入检查;local 只沿着已经声明检查选项的视图继续检查。

六、视图不一定都能更新

虽然视图看起来像表,但不是所有视图都适合执行插入和更新。

判断一个视图能否更新,核心要看视图中的一行能不能明确对应到基础表中的唯一一行。如果一个视图的结果经过了汇总、去重、分组或合并,就很难再反推出应该修改基础表中的哪一行。

比如下面这种聚合视图就不适合直接更新:

sql 复制代码
create view emp_salary_stat as
select count(*) as total_count, max(salary) as max_salary
from emp;

这个视图的结果是一条统计数据,不是 emp 表里的某一条员工记录。此时如果对 max_salary 做更新,MySQL 没法把它稳定地映射回基础表中的某一行。

常见会导致视图不可更新或不可插入的写法包括:

  1. 聚合函数或窗口函数,例如 sum、min、max、count。
  2. distinct。
  3. group by。
  4. having。
  5. union 或 union all。

MySQL 官方文档中也把这些结构列为影响视图可更新性的典型情况。实际开发中,如果视图涉及复杂连接、聚合统计或分组结果,更建议把它当成查询入口,不要把它当成写入入口。

七、视图的三个作用

视图的第一个作用是简化查询。常用的查询条件可以提前封装,后续直接查询视图即可。

第二个作用是提高安全性。基础表中可能有很多字段,但业务只需要暴露其中一部分,就可以通过视图只给出必要字段。例如只暴露 id 和 name,不暴露密码、手机号等敏感字段。

第三个作用是提高数据独立性。底层表结构调整时,如果能通过视图保持对外查询结果不变,上层 SQL 受到的影响就会小一些。

不过视图不是缓存。它保存的是查询逻辑,不是查询结果。使用视图时,仍然要关注基础表的数据量、索引和查询条件。

八、怎么验证这部分内容

学习视图时,可以按下面这个顺序自测:

sql 复制代码
create or replace view stu_v_1 as
select id, name
from user
where id <= 10
with check option;

show create view stu_v_1;

select * from stu_v_1;

insert into stu_v_1 values (2, 'zhangsan');

insert into stu_v_1 values (11, 'lisi');

drop view if exists stu_v_1;

验证时重点观察三件事。

第一,show create view 能不能看到视图定义。这个可以确认视图是否按预期创建。

第二,select 查询视图时,结果是否只包含视图条件允许的数据。

第三,带检查选项的视图在插入不满足条件的数据时是否会失败。没有真实执行环境时,不要把文章写成"已经执行成功",只能写成"可以这样验证"。

九、总结

视图可以理解为保存好的查询逻辑。它适合用来封装常用查询、隐藏不想暴露的字段、降低上层 SQL 对基础表结构的依赖。

使用视图时要记住三个判断:

  1. 只是查询复用,可以放心用视图简化 SQL。
  2. 需要通过视图写数据,要考虑 check option 是否限制了写入范围。
  3. 视图中出现聚合、去重、分组、合并等结构时,优先把它当成查询结果,不要默认它还能更新。

把这三个问题想清楚,视图就不会只是一个语法点,而是一个可以帮助我们整理查询边界的工具。

参考依据:MySQL 8.0 Reference Manual 中 create view、The View with check option Clause、Updatable and Insertable Views 相关章节。

相关推荐
jieyucx2 小时前
SQL 查询终极高阶通鉴:从零基础拆解到工业级多表联查、窗口函数与索引优化
数据库·sql
ai_coder_ai3 小时前
论 NoSQL 数据库技术及其应用
数据库·nosql
AOwhisky5 小时前
Redis 学习笔记(第一期):概述、安装配置与核心理论
运维·数据库·redis·笔记·学习·云计算
ytttr8735 小时前
C# 定时数据库备份工具
开发语言·数据库·c#
睡不醒男孩0308235 小时前
自建 Prometheus+Grafana 与 CLUP 深度监控 PG 集群有什么区别?
数据库·oracle
就叫_这个吧5 小时前
IDEA Mybatis xml文件,实现sql语句联想,自动填入补充
xml·mysql·intellij-idea·mybatis
AOwhisky5 小时前
Redis 学习笔记(第四期):高可用与集群(哨兵 + Cluster + 容器化)
linux·运维·数据库·redis·笔记·学习·缓存
猫猫聚会Ing5 小时前
数据库设计 Prompt 提示词 - 构建与迭代
数据库
上海云盾-小余5 小时前
源站隐藏实战:规避裸 IP 被直接攻击的完整方案
数据库·网络协议·tcp/ip