探究 MySQL 视图:功能、操作及注意事项


在 MySQL 数据库管理中,视图是一种强大且实用的工具。它作为从一个或多个表导出的虚拟表,不实际存储数据,却能基于查询语句呈现所需数据。在小型项目中视图或许并非必需,但在大型项目和复杂数据表结构下,视图优势尽显,能按需取用部分数据,定制查询视角,提升使用效率。


1. 视图概述

在 MySQL 中,视图(View)是从一个或多个表中导出的 虚拟表 ,它存储的是一个查询语句,当对视图进行查询时,实际上是执行该查询语句并返回结果。视图本身不存储数据,数据仍然存储在基表(视图所基于的表)中。

在这里插入图片描述
视图具备两大重要功能:一是它能够让我们仅取用表中的部分数据,而非整张表的全部信息;二是视图可依据不同用户的需求与权限,定制差异化的查询视角 。

  • 一些基本概念和介绍
  • 视图是一种 虚拟表 ,本身是 不具有数据 的,占用很少的内存空间,是 SQL 中的一个重要概念。
  • 视图建立在已有表的基础上,视图赖以建立的这些表称为 基表
  • 视图的创建和删除只影响视图本身,不影响对应的基表。
  • 对视图中的数据进行增加、删除和修改操作时,数据表中的数据会相应地发生变化,反之亦然。
  • 向视图提供数据内容的语句为 SELECT 语句,可以将视图理解为存储起来的 SELECT 语句
  • 视图是基表数据的另一种呈现形式。小型项目数据库可以不使用视图,但在大型项目及数据表复杂时,视图优势显著。它将常用查询结果集置于虚拟表,提升使用效率,便于理解与操作 。

2. 创建视图

在 MySQL 里,可以使用 CREATE VIEW 语句创建视图。使用语法如下:

# 在 CREATE VIEW 语句中嵌入子查询
CREATE [OR REPLACE]
[ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]
VIEW view_name [(column_list)]
AS select_statement
[WITH [CASCADED|LOCAL] CHECK OPTION]

各部分解释如下:

  • OR REPLACE:可选参数。若视图已存在,使用该参数可替换原视图。
  • ALGORITHM:可选参数,用于指定视图的处理算法,有三种取值。
    • UNDEFINED(默认值,由 MySQL 自行选择合适算法)
    • MERGE(将视图的查询与引用视图的查询合并)
    • TEMPTABLE(将视图的结果存储在临时表中)
  • view_name:要创建的视图名称。
  • column_list:可选参数,用于指定视图的列名。若未指定,视图列名与 SELECT 语句的列名相同。
  • select_statement:定义视图内容的 SELECT 查询语句,可从一个或多个表、其他视图中检索数据。
  • WITH [CASCADED | LOCAL] CHECK OPTION:可选参数,用于确保对视图进行的插入、更新操作符合视图定义的条件。
    • CASCADED 是默认值,会检查所有相关视图
    • LOCAL 仅检查当前视图。

因为完整的创建视图语法过于繁琐,所以为了提高编写效率,降低学习成本,增强代码可读性,且满足常见视图创建需求,让开发更高效、易上手。对创建语法进行了精简,如下:

CREATE [OR REPLACE] 
VIEW view_name [(column_list)]
AS select_statement;

2.1 创建单表视图

单表视图是基于单个表创建的视图。假设有一个名为 employees 的表,包含 employee_idemployee_namedepartmentsalary 列,通过不同需求展示创建单表视图的过程。

  • 简单视图:创建一个名为 employee_info 的视图,仅显示员工的姓名、邮箱和电话号码
CREATE VIEW employee_info AS
SELECT first_name,last_name,email,phone_number
FROM employees;

select * from employee_info;

在这里插入图片描述

  • 带条件的视图:创建一个名为 high_salary_employees 的视图,显示工资高于 5000 的员工信息
CREATE VIEW high_salary_employees AS
SELECT *
FROM employees
WHERE salary > 5000;

select first_name,last_name,salary from high_salary_employees;

在这里插入图片描述

  • 自定义列名的视图:创建一个名为 emp_info 的视图,自定义列名
CREATE VIEW emp_info (ID, Name, Dept_id, Pay) AS
SELECT employee_id, first_name, department_id, salary
FROM employees;

在这里插入图片描述

  • 注意事项
  • 创建视图需要有相应的权限,确保你有在指定数据库中创建视图的权限。
  • 单表视图在满足一定条件下可以进行更新操作(插入、更新、删除数据),但如果视图定义中包含 GROUP BYDISTINCT 等关键字,通常不支持更新。
  • 如果基表的结构发生变化,如列名修改、列删除等,可能会影响视图的正常使用,需要相应地修改视图定义。

实际上就是在 SQL 查询语句的基础上封装了视图 VIEW,这样就会基于 SQL 语句的结果集形成一张虚拟表。

在创建视图时,没有在视图名后面指定字段列表,则视图中字段列表默认和SELECT语句中的字段列表一致。如果SELECT语句中给字段取了别名,那么视图中的字段名和别名相同。

2.2 创建多表联合视图

多表联合视图基于多个表创建,通过连接操作将不同表的数据整合在一起。

创建一个名为 emp_dept_name 的视图,显示员工姓名和部门名。

CREATE VIEW emp_dept_name (员工姓名, 部门名) AS
SELECT employees.first_name, departments.department_name
FROM employees
JOIN departments ON employees.department_id = departments.department_id;

select * from emp_dept_name;

在这里插入图片描述

  • 注意事项
  • 创建视图需要有相应权限,要保证在指定数据库中有创建视图的权限,同时对参与联合的表有 SELECT 权限。
  • 多表联合视图的更新操作通常比单表视图复杂,并非所有的多表联合视图都支持更新。若视图定义里包含 GROUP BYDISTINCT、聚合函数等,往往不支持更新。
  • 连接条件的准确性十分关键,错误的连接条件会导致数据重复或缺失,影响视图数据的准确性。
  • 如果基表的结构发生改变,像列名修改、列删除等,可能会影响视图的正常使用,此时需要相应地修改视图定义。
  • 补充:利用视图对数据进行格式化

如果需要输出某个格式的内容,比如想输出员工姓名和对应的部门名,对应格式为 emp_name(department_name),就可以使用视图来完成数据格式化的操作:

CREATE VIEW emp_depart
AS
SELECT CONCAT(first_name,'(',department_name,')') AS emp_dept
FROM employees e JOIN departments d
WHERE e.department_id = d.department_id;

select * from emp_depart;

在这里插入图片描述

2.3 基于视图创建视图

在 MySQL 中,可以基于已有的视图创建新的视图。在需要进一步处理或筛选已有视图中的数据时非常有用,可以帮助逐步构建复杂的数据展示逻辑,同时保持代码的清晰和可维护性。

假设已经存在一个名为 customer_orders 的视图,该视图显示了客户的姓名和他们的订单日期,其定义如下:

CREATE VIEW customer_orders AS
SELECT customers.customer_name, orders.order_date
FROM customers
JOIN orders ON customers.customer_id = orders.customer_id;

想基于 customer_orders 视图创建一个新的视图 recent_customer_orders,只显示最近一个月内的订单。可以使用以下 SQL 语句:

CREATE VIEW recent_customer_orders AS
SELECT customer_name, order_date
FROM customer_orders
WHERE order_date >= CURDATE() - INTERVAL 1 MONTH;
  • 注意事项
  • 创建视图需要有相应的权限,确保你有在指定数据库中创建视图的权限,并且对所基于的视图有 SELECT 权限。
  • 基于视图创建视图可能会增加查询的复杂性,因为每次查询新视图时,数据库需要先执行原视图的查询,再执行新视图的查询。因此,在设计时要考虑性能问题,避免过度嵌套视图。
  • 与普通视图一样,基于视图创建的视图的更新操作也受到一定限制。如果原视图不支持更新,那么基于它创建的新视图通常也不支持更新。
  • 如果原视图的结构发生变化,如列名修改、列删除等,可能会影响新视图的正常使用,需要相应地修改新视图的定义。
  • 当我们创建好一张视图之后,还可以在它的基础上继续创建视图。

3. 查看视图

在 MySQL 中,查看视图的一些相关语法与查看数据表的类似。

# 查看数据库的表对象、视图对象 
SHOW TABLES;     # 直接展示当前所选数据库中的所有表名。 
SHOW FULL TABLES WHERE Table_type = 'VIEW';   # 显示当前数据库中的所有表和视图,并通过 Table_type 列区分它们。

# 查看表和视图的结构 
DESC / DESCRIBE 表名称;
DESC / DESCRIBE 视图名称;

# 查看表和视图信息(显示数据表的存储引擎、版本、数据行数和数据大小等)
SHOW TABLE STATUS LIKE '表名称';
SHOW TABLE STATUS LIKE '视图名称';
# 执行结果显示,注释Comment为VIEW,说明该表为视图,其他的信息为NULL,说明这是一个虚表。 

# 查看表和视图的详细定义信息
SHOW CREATE TABLE table_name;
SHOW CREATE VIEW view_name;

查看视图数据的方法与查看表数据的方法相同,使用 SELECT 语句即可。

SELECT * FROM view_name;     # view_name:要查询数据的视图名称。

示例:查询 customer_orders 视图中的所有数据:

SELECT * FROM customer_orders;

也可以根据需要指定要查询的列,添加筛选条件等,例如:

SELECT customer_name, order_date
FROM customer_orders
WHERE order_date > '2024-01-01';
  • 注意事项
  • 查看视图定义和数据都需要相应的权限。查看视图定义通常需要有 SHOW VIEW 权限,查看视图数据需要对视图有 SELECT 权限。
  • 如果视图的定义比较复杂,包含大量的连接、子查询等操作,查询视图数据可能会比较耗时。在这种情况下,可以考虑对视图所基于的表添加适当的索引来提高性能。

4. 更新视图的数据

在 MySQL 中,更新视图的数据并非总是可行,这取决于视图的定义方式。

4.1 一般可更新情况

并非所有视图都能进行数据更新(插入、更新、删除),通常满足以下条件的视图才可以更新:

  • 单表视图:基于单个表创建的视图,且视图定义中没有使用聚合函数(如 SUMCOUNTAVG 等)、GROUP BY 子句、DISTINCT 关键字、HAVING 子句等。
  • 可确定性更新:视图中的列必须直接引用基表的列,不能是表达式或计算结果,否则 MySQL 无法确定如何将更新操作映射到基表。
  • 基表有主键:如果视图基于多个表,每个表都应该有主键,并且视图定义中包含了这些主键列,以确保更新操作能准确应用到基表的特定行。
  • 插入数据(INSERT)

如果视图满足可更新条件,可以使用 INSERT 语句向视图中插入数据,插入的数据会自动反映到基表中。

INSERT INTO view_name (column1, column2, ...)
VALUES (value1, value2, ...);
  • view_name:要插入数据的视图名称。
  • column1, column2, ...:视图中的列名。
  • value1, value2, ...:要插入的值。

示例:假设存在一个基于 employees 表的视图 employee_info,包含 employee_idemployee_namedepartment 列,可使用以下语句插入数据:

INSERT INTO employee_info (employee_id, employee_name, department)
VALUES (101, 'John Doe', 'HR');
  • 更新数据(UPDATE

使用 UPDATE 语句可以更新视图中的数据,更新操作会影响到基表中对应的数据。

UPDATE view_name
SET column1 = value1, column2 = value2, ...
WHERE condition;
  • view_name:要更新数据的视图名称。
  • column1, column2, ...:视图中的列名。
  • value1, value2, ...:要更新的值。
  • condition:筛选条件,用于指定要更新的行。

示例:更新 employee_info 视图中 employee_id 为 101 的员工的部门信息:

UPDATE employee_info
SET department = 'Finance'
WHERE employee_id = 101;
  • 删除数据(DELETE

使用 DELETE 语句可以从视图中删除数据,删除操作会同步到基表中。

DELETE FROM view_name
WHERE condition;
  • view_name:要删除数据的视图名称。
  • condition:筛选条件,用于指定要删除的行。

示例:删除 employee_info 视图中 employee_id 为 101 的员工信息:

DELETE FROM employee_info
WHERE employee_id = 101;

4.2 不可更新的视图

若要使视图能够进行更新操作,视图中的行与底层基本表中的行之间必须呈现“一对一”的对应关系。此外,当视图定义出现以下情形时,该视图将不支持更新操作:

  • 若在定义视图时指定了 “ALGORITHM = TEMPTABLE”,则此视图不支持 INSERTDELETE 操作。
  • 若视图未包含基表中所有被定义为非空且未指定默认值的列,那么该视图不支持 INSERT 操作。
  • 若在定义视图的 SELECT 语句里使用了 JOIN 联合查询,此视图将不支持 INSERTDELETE 操作。
  • 若在定义视图的 SELECT 语句后的字段列表中运用了数学表达式或子查询,该视图既不支持 INSERT 操作,也不支持对使用了数学表达式、子查询的字段值进行 UPDATE 操作。
  • 若在定义视图的 SELECT 语句后的字段列表中使用了 DISTINCT、聚合函数、GROUP BYHAVINGUNION 等,此视图将不支持 INSERTUPDATEDELETE 操作。
  • 若在定义视图的 SELECT 语句中包含子查询,并且子查询引用了 FROM 后面的表,该视图将不支持 INSERTUPDATEDELETE 操作。
  • 若视图定义是基于一个不可更新视图,则此视图也不可更新。
  • 常量视图不支持更新操作。
## 举例:

mysql> CREATE OR REPLACE VIEW emp_dept
	-> (ename,salary,birthday,tel,email,hiredate,dname)
	-> AS SELECT ename,salary,birthday,tel,email,hiredate,dname
	-> FROM t_employee INNER JOIN t_department
	-> ON t_employee.did = t_department.did ;
Query OK, 0 rows affected (0.01 sec)

mysql> INSERT INTO emp_dept(ename,salary,birthday,tel,email,hiredate,dname)
	-> VALUES('张三',15000,'1995-01-08','18201587896',
	-> 'zs@atguigu.com','2022-02-14','新部门');
	
#ERROR 1393 (HY000): Can not modify more than one base table through a join view
'atguigu_chapter9.emp_dept'

从上面的SQL执行结果可以看出,在定义视图的SELECT语句中使用了JOIN联合查询,视图将不支持更新操作。

虽然可以更新视图数据,但总的来说,视图作为虚拟表 ,主要用于方便查询 ,不建议更新视图的数据。对视图数据的更改,都是通过对实际数据表里数据的操作来完成的。

5. 修改、删除视图

5.1 修改视图

修改视图主要有两种常见方式,分别是使用 CREATE OR REPLACE VIEW 语句和 ALTER VIEW 语句,下面为你详细介绍这两种方式。

  • 使用 CREATE OR REPLACE VIEW 语句

这种方式适用于不管视图是否存在,都可以进行创建或替换操作。如果视图不存在,它会创建一个新视图;如果视图已经存在,它会用新的定义替换原有的视图定义。使用语法如下:

CREATE OR REPLACE VIEW view_name [(column_list)]
AS
SELECT column1, column2, ...
FROM table_name
WHERE condition;

假设已经存在一个名为 customer_orders 的视图,其定义如下:

CREATE VIEW customer_orders AS
SELECT customers.customer_name, orders.order_date
FROM customers
JOIN orders ON customers.customer_id = orders.customer_id;

现在,你想修改这个视图,使其还显示订单的总金额。可以使用以下语句:

CREATE OR REPLACE VIEW customer_orders AS
SELECT customers.customer_name, orders.order_date, order_items.quantity * products.price AS total_amount
FROM customers
JOIN orders ON customers.customer_id = orders.customer_id
JOIN order_items ON orders.order_id = order_items.order_id
JOIN products ON order_items.product_id = products.product_id;
  • 使用 ALTER VIEW 语句

ALTER VIEW 语句专门用于修改已存在视图的定义。与 CREATE OR REPLACE VIEW 不同,若视图不存在,使用 ALTER VIEW 会报错。使用语法如下:

ALTER VIEW view_name [(column_list)]
AS
SELECT column1, column2, ...
FROM table_name
WHERE condition;

还是以 customer_orders 视图为例,若要修改该视图,使其只显示最近一个月内的订单。可以使用以下语句:

ALTER VIEW customer_orders AS
SELECT customers.customer_name, orders.order_date
FROM customers
JOIN orders ON customers.customer_id = orders.customer_id
WHERE orders.order_date >= CURDATE() - INTERVAL 1 MONTH;
  • 权限要求:修改视图需要有相应的权限,确保你有在指定数据库中修改视图的权限,并且对视图所基于的表有 SELECT 权限。
  • 视图更新影响:修改视图定义后,原有的基于该视图的查询可能需要相应调整,因为视图的结构或数据可能已经发生变化。
  • 数据完整性:修改视图时,要确保新的视图定义不会破坏数据的完整性,例如避免出现重复列名、无效的连接条件等。

5.2 删除视图

在 MySQL 里,可以使用 DROP VIEW 语句来删除视图。而且删除视图只是删除视图的定义,并不会删除基表的数据。 使用语法如下:

DROP VIEW [IF EXISTS] view_name [, view_name2, ...];
  • IF EXISTS:此为可选参数。若使用了该参数,当指定的视图不存在时,不会报错;若未使用,视图不存在则会报错。
  • view_name [, view_name2, ...]:要删除的视图名称,可同时指定多个视图,视图名之间用逗号分隔。
  • 删除单个视图

假设存在一个名为 customer_orders 的视图,要删除它,可使用以下语句:

DROP VIEW customer_orders;

若不确定该视图是否存在,为避免报错,可添加 IF EXISTS

DROP VIEW IF EXISTS customer_orders;
  • 删除多个视图

若要同时删除 customer_ordersproduct_sales 这两个视图,可使用以下语句:

DROP VIEW customer_orders, product_sales;

同样,为避免因视图不存在而报错,可添加 IF EXISTS

DROP VIEW IF EXISTS customer_orders, product_sales;
  • 权限要求:删除视图需要有相应的权限,确保你有在指定数据库中删除视图的权限。
  • 依赖关系:删除视图不会影响其基表的数据,但如果有其他查询、存储过程、触发器等依赖于该视图,删除后可能会导致这些对象无法正常工作。在删除视图之前,需确认是否有其他对象依赖于它。
  • 不可恢复性:删除视图是一个不可逆的操作,一旦删除,视图及其定义将永久丢失。因此,在执行删除操作前,请确保你确实需要删除该视图。

6. 总结

6.1 视图优点

  1. 操作简单 :将常用查询操作定义为视图,能让开发人员无需关注对应数据表结构、表间关联关系、业务逻辑及查询条件,仅操作视图就能完成任务,大幅简化了数据库操作。

  2. 减少数据冗余 :视图与实际数据表不同,它存储的是查询语句,使用时通过该查询语句获取结果集。视图本身不存储数据,不占数据存储资源,可减少数据冗余。

  3. 数据安全 :MySQL利用视图把用户对数据的访问限制在特定结果集上,用户无需直接操作数据表,视图就像用户和实际数据表间的虚拟表,体现了其隔离性。 依权限将用户数据访问限制于特定视图,用户借视图获取表中信息,无需查询数据表,一定程度上保障了数据安全。
    在这里插入图片描述

  4. 适应灵活多变的需求 :业务系统需求变动需改数据表结构时,工作量大,用视图可减少工作量,该方式在实际工作中应用广泛。

  5. 能够分解复杂的查询逻辑 :若数据库存在复杂查询逻辑,可分解问题,创建多个视图获取数据,再组合这些视图来实现复杂查询。

6.2 视图不足

  1. 维护成本高:实际数据表结构变更时,依赖该表的视图需同步维护,尤其是嵌套视图,维护难度和复杂度大幅增加。视图的查询语句可能涉及字段重命名或复杂逻辑,这使得维护成本显著提高。
  2. 可读性差:视图的创建SQL查询可能包含复杂逻辑,且字段可能被重命名,对于不熟悉视图创建逻辑的人员,理解和解读视图内容存在困难,降低了代码可读性。
  3. 潜在隐患大:由于视图维护复杂且可读性差,若维护不当,可能导致数据错误或不一致,成为系统运行的潜在隐患,影响系统的稳定性和可靠性。
  4. 增加数据库维护负担:在实际项目中,若视图数量过多,会显著增加数据库的维护成本,包括人力、时间和资源等方面的投入,给数据库管理带来较大压力。

所以,在创建视图的时候,要结合实际项目需求,综合考虑视图的优点和不足,这样才能正确使用视图,使系统整体达到最优。


综上所述,MySQL 视图功能丰富,无论是创建、查看,还是更新、修改和删除,都有其特定规则和注意事项。合理运用视图能优化数据库设计与使用,但在操作时要充分考虑权限、性能、数据完整性等因素,确保数据库稳定高效运行。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值