文章目录
在 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_id
、employee_name
、department
和 salary
列,通过不同需求展示创建单表视图的过程。
- 简单视图:创建一个名为
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 BY
、DISTINCT
等关键字,通常不支持更新。- 如果基表的结构发生变化,如列名修改、列删除等,可能会影响视图的正常使用,需要相应地修改视图定义。
实际上就是在 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 BY
、DISTINCT
、聚合函数等,往往不支持更新。- 连接条件的准确性十分关键,错误的连接条件会导致数据重复或缺失,影响视图数据的准确性。
- 如果基表的结构发生改变,像列名修改、列删除等,可能会影响视图的正常使用,此时需要相应地修改视图定义。
- 补充:利用视图对数据进行格式化
如果需要输出某个格式的内容,比如想输出员工姓名和对应的部门名,对应格式为 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 一般可更新情况
并非所有视图都能进行数据更新(插入、更新、删除),通常满足以下条件的视图才可以更新:
- 单表视图:基于单个表创建的视图,且视图定义中没有使用聚合函数(如
SUM
、COUNT
、AVG
等)、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_id
、employee_name
和 department
列,可使用以下语句插入数据:
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
”,则此视图不支持INSERT
和DELETE
操作。 - 若视图未包含基表中所有被定义为非空且未指定默认值的列,那么该视图不支持
INSERT
操作。 - 若在定义视图的
SELECT
语句里使用了JOIN
联合查询,此视图将不支持INSERT
和DELETE
操作。 - 若在定义视图的
SELECT
语句后的字段列表中运用了数学表达式或子查询,该视图既不支持INSERT
操作,也不支持对使用了数学表达式、子查询的字段值进行UPDATE
操作。 - 若在定义视图的
SELECT
语句后的字段列表中使用了DISTINCT
、聚合函数、GROUP BY
、HAVING
、UNION
等,此视图将不支持INSERT
、UPDATE
、DELETE
操作。 - 若在定义视图的
SELECT
语句中包含子查询,并且子查询引用了FROM
后面的表,该视图将不支持INSERT
、UPDATE
、DELETE
操作。 - 若视图定义是基于一个不可更新视图,则此视图也不可更新。
- 常量视图不支持更新操作。
## 举例:
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_orders
和 product_sales
这两个视图,可使用以下语句:
DROP VIEW customer_orders, product_sales;
同样,为避免因视图不存在而报错,可添加 IF EXISTS
:
DROP VIEW IF EXISTS customer_orders, product_sales;
- 权限要求:删除视图需要有相应的权限,确保你有在指定数据库中删除视图的权限。
- 依赖关系:删除视图不会影响其基表的数据,但如果有其他查询、存储过程、触发器等依赖于该视图,删除后可能会导致这些对象无法正常工作。在删除视图之前,需确认是否有其他对象依赖于它。
- 不可恢复性:删除视图是一个不可逆的操作,一旦删除,视图及其定义将永久丢失。因此,在执行删除操作前,请确保你确实需要删除该视图。
6. 总结
6.1 视图优点
-
操作简单 :将常用查询操作定义为视图,能让开发人员无需关注对应数据表结构、表间关联关系、业务逻辑及查询条件,仅操作视图就能完成任务,大幅简化了数据库操作。
-
减少数据冗余 :视图与实际数据表不同,它存储的是查询语句,使用时通过该查询语句获取结果集。视图本身不存储数据,不占数据存储资源,可减少数据冗余。
-
数据安全 :MySQL利用视图把用户对数据的访问限制在特定结果集上,用户无需直接操作数据表,视图就像用户和实际数据表间的虚拟表,体现了其隔离性。 依权限将用户数据访问限制于特定视图,用户借视图获取表中信息,无需查询数据表,一定程度上保障了数据安全。
-
适应灵活多变的需求 :业务系统需求变动需改数据表结构时,工作量大,用视图可减少工作量,该方式在实际工作中应用广泛。
-
能够分解复杂的查询逻辑 :若数据库存在复杂查询逻辑,可分解问题,创建多个视图获取数据,再组合这些视图来实现复杂查询。
6.2 视图不足
- 维护成本高:实际数据表结构变更时,依赖该表的视图需同步维护,尤其是嵌套视图,维护难度和复杂度大幅增加。视图的查询语句可能涉及字段重命名或复杂逻辑,这使得维护成本显著提高。
- 可读性差:视图的创建SQL查询可能包含复杂逻辑,且字段可能被重命名,对于不熟悉视图创建逻辑的人员,理解和解读视图内容存在困难,降低了代码可读性。
- 潜在隐患大:由于视图维护复杂且可读性差,若维护不当,可能导致数据错误或不一致,成为系统运行的潜在隐患,影响系统的稳定性和可靠性。
- 增加数据库维护负担:在实际项目中,若视图数量过多,会显著增加数据库的维护成本,包括人力、时间和资源等方面的投入,给数据库管理带来较大压力。
所以,在创建视图的时候,要结合实际项目需求,综合考虑视图的优点和不足,这样才能正确使用视图,使系统整体达到最优。
综上所述,MySQL 视图功能丰富,无论是创建、查看,还是更新、修改和删除,都有其特定规则和注意事项。合理运用视图能优化数据库设计与使用,但在操作时要充分考虑权限、性能、数据完整性等因素,确保数据库稳定高效运行。