25.11 MySQL 视图

2024-04-03_175716

1. 常见的数据库对象

对象描述
表(TABLE)存储数据的逻辑单元, 以行和列的形式存在, 列就是字段, 行就是记录.
数据字典系统表, 存放数据库相关信息的表. 数据通常由数据库系统维护, 程序员通常不可修改, 只可查看.
约束(CONSTRAINT)执行数据校验的规则, 用于保证数据完整性的规则.
视图(VIEW)一个或多个数据表里的数据的逻辑显示. 视图并不存储数据, 而是提供一个定制化的数据展示方式.
索引(INDEX)用于提高查询性能, 相当于书的目录. 通过索引, 数据库系统可以快速定位到所需的数据.
存储过程(PROCEDURE)用于完成一次完整的业务处理, 没有返回值, 但可通过传出参数将多个值传给调用环境.
存储函数(FUNCTION)用于完成一次特定的计算, 具有一个返回值.
触发器(TRIGGER)相当于一个事件监听器. 当数据库发生特定事件(如插入, 更新或删除操作)后, 触发器被触发, 完成相应的处理.

2. 视图

2.1 简介

在MySQL中, 视图(View)是一个虚拟的表, 其内容由查询定义.
视图并不存储数据, 它只包含定义视图的SQL语句, 也因此视图占用的内存空间相对较少.
当查询视图时, MySQL会执行这些SQL语句并返回结果.视图在多种场景下都非常有用, 以下是一些建议何时使用视图的情形:
* 1. 简化复杂的SQL查询: 当你有一个复杂的SQL查询, 并且这个查询被多个地方重复使用, 你可以将这个查询定义为一个视图.这样, 每次需要这个查询的结果时, 只需要简单地查询这个视图即可.* 2. 抽象数据: 视图可以隐藏数据的复杂性, 只展示用户需要的部分数据.例如, 你可能有一个包含大量字段的表, 但某些用户或应用程序只需要其中的几个字段.通过创建一个只包含这些字段的视图, 你可以简化对这些用户的数据访问.* 3. 安全性: 通过视图, 你可以限制用户对基础数据的访问.例如, 你可以创建一个视图, 该视图只显示某些用户有权查看的数据行或列.这样, 即使用户尝试直接查询基础表, 他们也只能看到视图所允许的数据.* 4. 逻辑数据独立性: 当基础表的结构发生变化时(例如, 添加, 删除或修改列), 如果有很多地方引用了这些表, 那么修改这些引用可能会很繁琐.通过使用视图, 你可以将这些引用指向视图而不是基础表.这样, 当基础表结构发生变化时, 你只需要更新视图的定义, 而无需修改所有引用.* 5. 合并数据: 视图可以用于合并来自多个表的数据, 以提供一个统一的视图.这对于需要跨多个表查询数据的场景非常有用.* 6. 遵守业务规则: 你可以通过视图来实施业务规则, 确保用户只能看到或修改符合规则的数据.例如, 你可以创建一个视图, 该视图只显示库存量大于零的产品.* 7. 历史数据或计算字段: 视图可以用于展示基于基础表计算得出的字段, 或者用于展示历史数据的快照.需要注意的是, 虽然视图有很多优点, 但它们也有一些限制和潜在的性能问题.
例如, 对视图进行插入, 更新或删除操作可能会受到限制, 具体取决于视图的定义和基础表的结构.
此外, 如果视图基于复杂的查询, 那么查询视图本身可能会比直接查询基础表更慢.
因此, 在决定使用视图之前, 最好先评估其适用性和潜在影响.

image-20240402141843168

视图一方面可以帮我们使用表的一部分而不是所有的表,
另一方面也可以针对不同的用户制定不同的查询视图.
比如, 针对一个公司的销售人员, 我们只想给他看部分数据, 而某些特殊的数据, 比如采购的价格, 则不会提供给他.
再比如, 人员薪酬是个敏感的字段, 那么只给某个级别以上的人员开放, 其他人的查询视图中则不提供这个字段.

2.2 视图的理解

视图是SQL中的一个重要概念, 它允许用户通过预定义的查询语句来访问数据, 而不需要每次都编写复杂的查询.
视图基于已有的表(称为基表或基础表)创建, 并且可以根据需要引用一个或多个基表.

image-20240402163454199

视图的创建和删除仅对视图本身产生影响, 并不会改变其依赖的基表结构或数据.
然而, 当对视图执行插入, 删除或修改操作时, 这些变化会反映到基表中, 反之亦然.
这是因为视图本质上是一个基于SQL查询的虚拟表, 它并不存储实际数据, 而是根据查询语句动态生成数据.向视图提供数据内容的核心语句是SELECT语句, 因此, 可以将视图视为一个预定义的, 存储起来的SELECT查询.
数据库中的视图并不保存数据本身, 真正的数据存储在数据表中.
因此, 当通过视图对数据进行增删改操作时, 这些变更会直接作用在基表上, 确保数据的完整性和一致性.视图是向用户展示基表数据的一种灵活且高效的方式.
在小型项目中, 可能不需要频繁使用视图, 但在大型项目或数据表结构复杂的情况下, 视图的价值就显得尤为重要.
它可以将经常需要查询的结果集封装成一个虚拟表, 从而提高查询效率, 简化复杂操作, 并为用户提供更加清晰和定制化的数据视图.
理解和使用视图对于数据库管理和应用开发都是非常有益的.

3. 创建视图

3.1 语法格式

在MySQL中, 创建视图的完整语法如下:CREATE VIEW view_name AS  
SELECT column1, column2, ...  
FROM table_name  
WHERE condition;这里, view_name是你要创建的视图的名称, SELECT语句定义了视图的内容, 它指定了从哪个表中选择哪些列, 以及任何可能的过滤条件.注意事项:
创建视图需要具有足够的权限, 并且视图所依赖的基表在视图创建后不能随意删除或修改, 否则可能会导致视图失效或查询错误.
如果基表结构发生变化, 可能需要相应地更新视图定义.
以下是一个具体的例子, 假设我们有一个名为employees的表,
包含id, name, department_id, 和salary列, 我们想要创建一个视图, 该视图只显示薪资超过某个特定值的员工:CREATE VIEW high_salary_employees AS  
SELECT id, name, salary  
FROM employees  
WHERE salary > 50000;在这个例子中, 我们创建了一个名为 high_salary_employees的视图,
它包含了employees表中薪资超过50000的员工的id, name, 和salary列.

3.2 示例

-- 使用数据库:
mysql> USE db0;
Database changed-- 创建视图:
mysql> CREATE VIEW high_salary_employees
AS
SELECT employee_id, first_name, salary
FROM  atguigudb.employees
WHERE  salary > 5000;
Query OK, 0 rows affected (0.01 sec)-- 查看视图的数据:
mysql> SELECT * FROM high_salary_employees;
+-------------+-------------+----------+
| employee_id | first_name  | salary   |
+-------------+-------------+----------+
|         100 | Steven      | 24000.00 |
|         ... | ...         | ...      |  -- 省略
|         204 | Hermann     | 10000.00 |
|         205 | Shelley     | 12000.00 |
|         206 | William     |  8300.00 |
+-------------+-------------+----------+
58 rows in set (0.00 sec)
实际上就是我们在 SQL 查询语句的基础上封装了视图 VIEW, 这样就会基于 SQL 语句的结果集形成一张虚拟表.

image-20240402214029426

-- 创建年薪视图:
mysql> CREATE VIEW annual_salary
AS
SELECT 
employee_id AS `emp_id`,
first_name AS `name`,
salary * 12 * (1 + IFNULL(commission_pct, 0)) AS `year_salary`
FROM atguigudb.employees;
Query OK, 0 rows affected (0.01 sec)-- 查看年薪视图:
mysql> SELECT * FROM annual_salary;
+--------+-------------+-------------+
| emp_id | name        | year_salary |
+--------+-------------+-------------+
|    100 | Steven      |   288000.00 |
|    101 | Neena       |   204000.00 |
|    102 | Lex         |   204000.00 |
|    103 | Alexander   |   108000.00 |
|    104 | Bruce       |    72000.00 |
|    ... | ...         |         ... |  -- 省略
+--------+-------------+-------------+
107 rows in set (0.00 sec)

3.3 设置字段名称

在创建视图时, 没有在视图名后面指定字段列表, 则视图中字段列表默认和SELECT语句中的字段列表一致.
如果SELECT语句中给字段取了别名, 那么视图中的字段名和别名相同.在MySQL中, 设置视图字段名称的方式:
* 1. 方式一: 在SELECT语句中使用AS关键字为字段设置别名.
* 2. 方式二: 在CREATE VIEW语句的列定义部分直接指定字段名称.
-- 创建年薪视图, 并为字段设置名称:
mysql> CREATE VIEW annual_salary2
AS
SELECT employee_id AS `ID_NUMBER`, 
first_name AS `NAME`,
salary * 12 * (1 + IFNULL(commission_pct, 0)) AS `ANN_SALARY`
FROM atguigudb.employees;
Query OK, 0 rows affected (0.01 sec-- 查看年薪视图:       
mysql> SELECT * FROM annual_salary2;
+-----------+-------------+------------+
| ID_NUMBER | NAME        | ANN_SALARY |
+-----------+-------------+------------+
|       100 | Steven      |  288000.00 |
|       101 | Neena       |  204000.00 |
|       102 | Lex         |  204000.00 |
|       103 | Alexander   |  108000.00 |
|       104 | Bruce       |   72000.00 |
|       105 | David       |   57600.00 |
|       ... | ...         |   ...      |   -- 省略       
+-----------+-------------+------------+
107 rows in set (0.00 sec)
-- 方式二:
mysql> CREATE VIEW annual_salary3
(ID_NUMBER, NAME, ANN_SALARY)  -- 设置别名
AS
SELECT employee_id, first_name,
salary * 12 * (1 + IFNULL(commission_pct, 0))
FROM atguigudb.employees;
Query OK, 0 rows affected (0.01 sec)-- 查看年薪视图:       
mysql> SELECT * FROM annual_salary3;
+-----------+-------------+------------+
| ID_NUMBER | NAME        | ANN_SALARY |
+-----------+-------------+------------+
|       100 | Steven      |  288000.00 |
|       101 | Neena       |  204000.00 |
|       102 | Lex         |  204000.00 |
|       103 | Alexander   |  108000.00 |
|       ... | ...         |   ...      |   -- 省略       
+-----------+-------------+------------+
107 rows in set (0.00 sec)

3.4 多表联合视图

多表联合视图(也称为多表视图)是一个虚拟的表, 它由多个表通过连接操作组合而成.
这个视图为用户提供了一个统一的, 简化的接口来查询多个表中的数据, 而无需重写的连接查询.
-- 内连接, 查看所有员工id, 员工姓名, 部门名称(没有部门不显示):
mysql> CREATE VIEW emp_depname
AS
SELECT emp.employee_id AS `emp_id`, emp.first_name AS `name`, dep.department_name
FROM atguigudb.employees AS `emp`
INNER JOIN atguigudb.departments AS `dep`
ON emp.department_id = dep.department_id;
Query OK, 0 rows affected (0.01 sec)-- 查看视图:  
mysql> SELECT * FROM emp_depname2;
+--------+-------------+------------------+
| emp_id | name        | department_name  |
+--------+-------------+------------------+
|    200 | Jennifer    | Administration   |
|    201 | Michael     | Marketing        |
|    202 | Pat         | Marketing        |
|    114 | Den         | Purchasing       |
|    115 | Alexander   | Purchasing       |
|    116 | Shelli      | Purchasing       |
|    117 | Sigal       | Purchasing       |
|    ... | ...         | ...              |   -- 省略       
+--------+-------------+------------------+
106 rows in set (0.00 sec)
-- 右连接, 查看所有员工id, 员工姓名, 部门名称(没有部门也显示):
mysql> CREATE VIEW emp_depname2
AS
SELECT emp.employee_id AS `emp_id`, emp.first_name AS `name`, dep.department_name
FROM atguigudb.employees AS `emp`
LEFT JOIN atguigudb.departments AS `dep`
ON emp.department_id = dep.department_id;
Query OK, 0 rows affected (0.01 sec)-- 查看视图:  
mysql> SELECT * FROM emp_depname2;
+--------+-------------+------------------+
| emp_id | name        | department_name  |
+--------+-------------+------------------+
|    100 | Steven      | Executive        |
|    101 | Neena       | Executive        |
|    102 | Lex         | Executive        |
|    103 | Alexander   | IT               |
|    104 | Bruce       | IT               |
|    ... | ...         | ...              |   -- 省略       
+--------+-------------+------------------+
107 rows in set (0.00 sec)
-- 获取部门的最高工资, 最低工资, 平均工资:
mysql> CREATE VIEW emp_min_max_avg
(name, minsal, maxsal, avgsal)
AS
SELECT dep.department_name, MIN(emp.salary), MAX(emp.salary), AVG(emp.salary)
FROM atguigudb.employees AS `emp`
INNER JOIN atguigudb.departments AS `dep`
ON emp.department_id = dep.department_id
GROUP BY dep.department_name;
Query OK, 0 rows affected (0.01 sec)-- 查看视图:  
mysql> SELECT * FROM emp_min_max_avg;
+------------------+----------+----------+--------------+
| name             | minsal   | maxsal   | avgsal       |
+------------------+----------+----------+--------------+
| Executive        | 17000.00 | 24000.00 | 19333.333333 |
| IT               |  4200.00 |  9000.00 |  5760.000000 |
| Finance          |  6900.00 | 12000.00 |  8600.000000 |
| Purchasing       |  2500.00 | 11000.00 |  4150.000000 |
| Shipping         |  2100.00 |  8200.00 |  3475.555556 |
| Sales            |  6100.00 | 14000.00 |  8955.882353 |
| Administration   |  4400.00 |  4400.00 |  4400.000000 |
| Marketing        |  6000.00 | 13000.00 |  9500.000000 |
| Human Resources  |  6500.00 |  6500.00 |  6500.000000 |
| Public Relations | 10000.00 | 10000.00 | 10000.000000 |
| Accounting       |  8300.00 | 12000.00 | 10150.000000 |
+------------------+----------+----------+--------------+
11 rows in set (0.00 sec)

3.4 格式化数据

在创建视图时, 可以使用SQL的字符串函数来格式化数据, 以便在视图中以特定的格式展示.
可以使用各种内置函数来操作数据, 以满足特定的输出需求.比如, 我们想输出员工姓名和对应的部门名, 对应格式为emp_name(department_name),
就可以使用视图来完成数据格式化的操作:
-- 创建视图:
mysql> CREATE VIEW emp_depname3
AS
SELECT CONCAT(emp.first_name,'(', dep.department_name,')' ) AS emp_depname
FROM atguigudb.employees AS `emp`
INNER JOIN atguigudb.departments AS `dep`
ON emp.department_id = dep.department_id;
Query OK, 0 rows affected (0.00 sec)-- 查看视图:  
mysql> SELECT * FROM emp_depname;
+---------------------------+
| emp_depname               |
+---------------------------+
| Jennifer(Administration)  |
| Michael(Marketing)        |
| ...                       |  -- 省略       
+---------------------------+
106 rows in set (0.00 sec)

3.5 基于视图创建视图

在SQL中, 可以基于一个已经存在的视图来创建另一个视图.
通过组合多个视图或者在一个视图的基础上进一步处理数据来创建更复杂的视图.举例: 联合'emp_depname''annual_salary'视图查询员工姓名, 部门名称, 年薪信息创建emp_depname_anasal视图:
-- 创建视图:
mysql> CREATE VIEW emp_depname_anasal
AS
SELECT emp.emp_id, emp.name, ann.year_salary, emp.department_name
FROM emp_depname AS `emp`
INNER JOIN annual_salary AS `ann`
ON emp.emp_id = ann.emp_id;
Query OK, 0 rows affected (0.01 sec)-- 查看视图:
mysql> SELECT * FROM emp_depname_anasal;
+--------+-------------+-------------+------------------+
| emp_id | name        | year_salary | department_name  |
+--------+-------------+-------------+------------------+
|    100 | Steven      |   288000.00 | Executive        |
|    101 | Neena       |   204000.00 | Executive        |
|    102 | Lex         |   204000.00 | Executive        |
|    103 | Alexander   |   108000.00 | IT               |
|    104 | Bruce       |    72000.00 | IT               |
|    ... | ...         |         ... | ...              |  -- 省略     
+--------+-------------+-------------+------------------+
106 rows in set (0.00 sec)

4. 查看视图

语法1: 查看数据库的表对象, 视图对象: SHOW TABLES;
-- 查看视图对象:
mysql> SHOW TABLES;
+--------------------+
| Tables_in_db0      |
+--------------------+
| annual_salary      |
| emp_depname        |
| emp_depname2       |
| ...                |
+--------------------+
语法2: 查看视图的结构: DESC / DESCRIBE view_name;
-- 查看视图结构:
mysql> DESC annual_salary;
+-------------+--------------+------+-----+---------+-------+
| Field       | Type         | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+-------+
| emp_id      | int          | NO   |     | 0       |       |
| name        | varchar(20)  | YES  |     | NULL    |       |
| year_salary | double(22,2) | YES  |     | NULL    |       |
+-------------+--------------+------+-----+---------+-------+
3 rows in set (0.01 sec)
语法3: 查看视图的属性信息(数据表的存储引擎, 版本, 数据行数和数据大小等): SHOW TABLE STATUS LIKE 'view_name'\G
-- 执行结果显示, 注释Comment为VIEW, 说明该表为视图, 其他的信息为NULL, 说明这是一个虚表:
mysql> SHOW TABLE STATUS LIKE 'annual_salary';

image-20240403124046457

语法4: 查看视图的详细定义信息: SHOW CREATE VIEW view_name;
mysql> SHOW CREATE VIEW annual_salary;

image-20240403125454863

5. 更新视图的数据

MySQL支持使用INSERT, UPDATE和DELETE语句对视图中的数据进行插入, 更新和删除操作.
当视图中的数据发生变化时, 数据表中的数据也会发生变化, 反之亦然.

5.1 更行示例

-- 创建表格:
CREATE TABLE emp0(id INT,name VARCHAR(20),phone INT
);
Query OK, 0 rows affected (0.02 sec)-- 插入数据:
mysql> INSERT INTO emp0 VALUES(1, 'kid', 123456);
Query OK, 1 row affected (0.00 sec)-- 创建视图:
mysql> CREATE VIEW emp0_view
AS 
SELECT * FROM emp0;
Query OK, 0 rows affected (0.01 sec)-- 查看视图:
mysql> SELECT * FROM emp0_view;
+------+------+--------+
| id   | name | phone  |
+------+------+--------+
|    1 | kid  | 123456 |
+------+------+--------+
1 row in set (0.00 sec)-- 修改视图:
mysql> UPDATE emp0_view SET phone = 10086 WHERE name = 'kid';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0-- 查看视图:
mysql> SELECT * FROM emp0_view;
+------+------+-------+
| id   | name | phone |
+------+------+-------+
|    1 | kid  | 10086 |
+------+------+-------+
1 row in set (0.00 sec)-- 查看表格:
mysql> SELECT * FROM emp0;
+------+------+-------+
| id   | name | phone |
+------+------+-------+
|    1 | kid  | 10086 |
+------+------+-------+
1 row in set (0.00 sec)

5.2 删除示例

mysql>  DELETE FROM emp0_view  WHERE name = 'kid';
Query OK, 1 row affected (0.01 sec)-- 查看视图:
mysql> SELECT * FROM emp0_view;
Empty set (0.00 sec)-- 查看表格:
mysql> SELECT * FROM emp0;
Empty set (0.00 sec)

5.3 不可更新的视图

要使视图保持可更新性, 必须确保视图中的每一行与底层基本表中的行之间存在一对一的映射关系.
然而, 在多种情况下, 视图可能不支持更新操作.
以下是这些情况的详细解释和润色后的表述:
* 1. 使用临时表算法: 当在定义视图时指定了'ALGORITHM = TEMPTABLE', 这表示视图将使用临时表来存储查询结果.由于临时表不支持对原始数据的直接更新, 因此这样的视图将不支持INSERT和DELETE操作.* 2. 缺少非空列: 如果视图中没有包含基本表中所有被定义为非空且未指定默认值的列, 那么当尝试向视图中插入数据时, 可能会因为缺少这些必要的列而无法完成, 因此这样的视图不支持INSERT操作.* 3. 使用JOIN操作: 当定义视图的SELECT语句中使用了JOIN联合查询时, 由于JOIN操作可能涉及多个表的数据组合,这种组合可能导致无法直接定位到基本表中的具体行进行更新或删除, 因此这样的视图不支持INSERT和DELETE操作.* 4. 使用数学表达式或子查询: 如果定义视图的SELECT语句后的字段列表中使用了数学表达式或子查询,这些操作通常会产生计算后的值或基于其他数据的派生值, 这些值并不直接对应基本表中的实际数据,因此这样的视图不支持INSERT操作, 也不支持UPDATE中对使用数学表达式或子查询字段值的修改.* 5. 使用DISTINCT, 聚合函数等: 当SELECT语句后的字段列表中使用DISTINCT关键字进行去重, 或者使用聚合函数如SUM, COUNT等.以及使用GROUP BY, HAVING, UNION等操作时, 这些操作通常会对数据进行汇总或组合, 导致无法直接映射到基本表中的具体行.因此这样的视图不支持INSERT, UPDATE和DELETE操作.* 6. 子查询引用FROM后的表: 如果定义视图的SELECT语句中包含了子查询, 并且子查询中引用了FROM子句后面指定的表,这种结构可能导致视图无法准确反映基本表中的数据变化, 因此这样的视图不支持INSERT, UPDATE和DELETE操作.* 7. 基于不可更新视图: 如果视图的定义是基于另一个已经不可更新的视图,那么由于底层视图的限制, 这个视图也将继承其不可更新的特性.* 8. 常量视图: 常量视图是只包含常量值或字面量的视图, 由于其不涉及任何基本表数据, 因此自然不支持任何更新操作.虽然可以更新视图数据, 但总的来说, 视图作为虚拟表主要用于方便查询, 不建议更新视图的数据.
对视图数据的更改, 都是通过对实际数据表里数据的操作来完成的.

6. 修改视图

替换视图语法: CREATE OR REPLACE VIEW view_name;
如果同名的视图已经存在, 则替换它. 这个命令让你能够修改视图的定义, 而无需先删除现有的视图再重新创建它.修改视图语法: ALTER VIEW view_name;
mysql> SHOW TABLES;
+--------------------+
| Tables_in_db0      |
+--------------------+
| annual_salary      |
| ...                |
+--------------------+-- annual_salary视图已经存在, 替换掉:
mysql> CREATE OR REPLACE VIEW annual_salary  -- 不算提成版本:
AS
SELECT 
employee_id AS `emp_id`,
first_name AS `name`,
salary * 12 AS `year_salary`
FROM atguigudb.employees;
Query OK, 0 rows affected (0.01 sec)-- 查看视图:
mysql> SELECT * FROM annual_salary;
+--------+-------------+-------------+
| emp_id | name        | year_salary |
+--------+-------------+-------------+
|    100 | Steven      |   288000.00 |
|    101 | Neena       |   204000.00 |
|    102 | Lex         |   204000.00 |
|    103 | Alexander   |   108000.00 |
|    ... | ...         |   ...       |
+--------+-------------+-------------+
-- 计算半年薪资:
mysql> ALTER VIEW annual_salary  -- 不算提成版本:
AS
SELECT 
employee_id AS `emp_id`,
first_name AS `name`,
salary * 6 AS `salary_6`
FROM atguigudb.employees;
Query OK, 0 rows affected (0.01 sec)-- 查看视图:
mysql> SELECT * FROM annual_salary;
+--------+-------------+-----------+
| emp_id | name        | salary_6  |
+--------+-------------+-----------+
|    100 | Steven      | 144000.00 |
|    101 | Neena       | 102000.00 |
|    102 | Lex         | 102000.00 |
|    103 | Alexander   |  54000.00 |
|    104 | Bruce       |  36000.00 |
|    105 | David       |  28800.00 |
|    106 | Valli       |  28800.00 |
|    ... | ...         |   ...     |
+--------+-------------+-----------+

7. 删除视图

删除视图的语法: DROP VIEW IF EXISTS 视图名称;
删除视图只是删除视图的定义, 并不会删除基表的数据.注意事项:
如果基于视图a, b创建了新的视图c, 将视图a或者视图b删除, 会导致视图c的查询失败.
这样的视图c需要手动删除或修改, 否则影响使用.
mysql> DROP VIEW IF EXISTS annual_salary;
Query OK, 0 rows affected (0.00 sec)

8. 总结

8.1 视图的优点

视图在数据库设计和应用中确实扮演了重要的角色, 主要的优点如下:
* 1. 操作简单: 视图可以隐藏数据的复杂性, 使得用户只需要关注他们关心的数据部分, 而不需要了解底层数据表的结构和关联关系.通过视图, 开发人员可以编写一次复杂的查询逻辑, 并在多个地方重复使用这个视图, 从而简化了开发过程.
* 2. 减少数据冗余: 视图本身不存储数据, 它只存储查询语句.因此, 视图不会占用额外的存储空间, 这有助于减少数据的冗余和存储成本.当底层数据表中的数据发生变化时, 视图会自动反映这些变化, 无需手动更新.
* 3. 数据安全: 通过视图, 可以限制用户对数据的访问权限.例如, 可以创建一个只包含部分字段或部分记录的视图, 然后只允许用户通过这个视图来访问数据.视图还可以隐藏敏感数据, 例如密码或敏感的业务逻辑, 从而提高数据的安全性.
* 4. 适应灵活多变的需求: 当业务需求发生变化时, 如果直接修改数据表的结构可能会影响到多个应用程序或查询.而通过使用视图, 可以在不修改底层数据表的情况下, 通过修改视图的定义来满足新的需求.视图提供了一种抽象层, 使得应用程序与底层数据表之间的耦合度降低, 从而更容易适应变化.
* 5. 能够分解复杂的查询逻辑: 对于复杂的查询逻辑, 可以将其分解为多个简单的查询, 并将这些查询封装在视图中.然后, 可以通过组合这些视图来构建更复杂的查询, 从而简化查询逻辑的管理和维护.通过分解复杂的查询逻辑, 还可以提高查询的性能, 因为每个视图都可以针对其特定的查询进行优化.总之, 视图提供了一种强大而灵活的工具来管理, 简化和优化数据库访问和查询逻辑, 
使得开发人员能够更高效地处理数据库操作, 同时保障数据的安全性和完整性.

image-20240403145913127

8.2 视图的缺点

视图的缺点主要包括以下几个方面:
* 1. 额外开销: 视图是基于SQL查询的, 它不存储实际的数据, 而是存储了查询数据的SQL语句.因此, 每次通过视图进行数据查询时, 都需要执行其背后的SQL语句, 这个执行过程包括解析视图定义, 优化查询计划以及执行实际的查询操作, 这些步骤都需要消耗一定的计算资源.相比之下, 一个简单的SQL查询可能更快.
* 2. 维护复杂: 当底层数据表的结构发生变化(如添加, 删除或修改字段), 相关的视图可能需要进行相应的更新.这是因为视图是基于底层数据表构建的, 如果底层数据表的结构发生变化, 视图可能就不再准确反映数据, 甚至可能变得无效.特别是在大型系统中, 视图数量众多, 维护起来可能相当繁琐.此外, 如果视图之间存在依赖关系(如嵌套视图), 修改一个视图可能会影响到其他多个视图, 进一步增加了维护的复杂性.
* 3. 可读性和可维护性挑战: 创建视图的SQL查询可能包含复杂的逻辑, 如字段重命名, 条件筛选, 聚合计算等.这些复杂的查询逻辑可能使得视图变得难以理解和维护.对于其他开发人员来说, 可能需要花费更多的时间和精力来理解视图的逻辑和功能.此外, 如果视图逻辑过于复杂, 也增加了出错的可能性, 进一步影响了系统的稳定性和可靠性.为了优化视图的使用和管理, 可以采取以下措施:
* 1. 精简视图数量: 避免创建不必要的视图, 只针对那些经常使用的, 能够简化查询逻辑的数据创建视图.* 2. 简化视图逻辑: 尽量保持视图逻辑的简洁性, 避免在视图中进行复杂的计算或处理.复杂的逻辑可以放在应用程序层面处理.* 3. 定期审查和维护: 定期审查现有视图, 确保其与实际数据表保持同步, 并根据需要进行更新或优化.* 4. 文档化视图: 为每个视图提供详细的文档说明, 包括其用途, 依赖关系, 查询逻辑等, 以便其他开发人员能够理解和维护.* 5. 使用命名规范: 为视图制定统一的命名规范, 以便快速识别和理解视图的含义和用途.* 6. 限制嵌套视图的使用: 尽量避免使用嵌套视图, 以减少维护的复杂性和潜在风险, 如果必须使用嵌套视图, 应确保其逻辑清晰, 易于理解.通过综合考虑以上措施, 可以更好地利用视图的优点, 同时降低其可能带来的维护成本, 使系统整体达到最优状态.

9. 练习

9.1 练习1

-- 1. 使用表employees创建视图employee_vu, 其中包括姓名(LAST_NAME), 员工号(EMPLOYEE_ID)部门号(DEPARTMENT_ID):
mysql> CREATE VIEW employee_vu
(LAST_NAME, EMPLOYEE_ID, DEPARTMENT_ID)
AS
SELECT employee_id, last_name, department_id
FROM atguigudb.employees;
Query OK, 0 rows affected (0.01 sec)
-- 2. 显示视图的结构:
mysql> DESC employee_vu;
+---------------+-------------+------+-----+---------+-------+
| Field         | Type        | Null | Key | Default | Extra |
+---------------+-------------+------+-----+---------+-------+
| LAST_NAME     | int         | NO   |     | 0       |       |
| EMPLOYEE_ID   | varchar(25) | NO   |     | NULL    |       |
| DEPARTMENT_ID | int         | YES  |     | NULL    |       |
+---------------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
-- 3. 查询视图中的全部内容:
mysql> SELECT * FROM employee_vu;
+-----------+-------------+---------------+
| LAST_NAME | EMPLOYEE_ID | DEPARTMENT_ID |
+-----------+-------------+---------------+
|       100 | King        |            90 |
|       101 | Kochhar     |            90 |
|       102 | De Haan     |            90 |
|       103 | Hunold      |            60 |
|       ... | ...         |           ... |  -- 省略
+-----------+-------------+---------------+
-- 4. 将视图中的数据限定在部门号是80的范围内:
mysql> ALTER VIEW employee_vu
(LAST_NAME, EMPLOYEE_ID, DEPARTMENT_ID)
AS
SELECT employee_id, last_name, department_id
FROM atguigudb.employees
WHERE department_id = 80;
Query OK, 0 rows affected (0.01 sec

9.2 练习2

-- 复制表格
mysql> CREATE TABLE emps
AS
SELECT * FROM atguigudb.employees;
Query OK, 107 rows affected, 2 warnings (0.02 sec)
Records: 107  Duplicates: 0  Warnings: 2
-- 1. 创建视图emp_v1,要求查询电话号码以'011'开头的员工姓名和工资, 邮箱:
mysql> CREATE VIEW emp_v1 
AS 
SELECT first_name, salary, email
FROM emps
WHERE phone_number LIKE '011%';
Query OK, 0 rows affected (0.01 sec)-- 查看视图:
mysql> SELECT * FROM emp_v1;
+-------------+----------+----------+
| first_name  | salary   | email    |
+-------------+----------+----------+
| John        | 14000.00 | JRUSSEL  |
| Karen       | 13500.00 | KPARTNER |
| ...         | ...      | ...      |  -- 省略
| Jack        |  8400.00 | JLIVINGS |
| Kimberely   |  7000.00 | KGRANT   |
| Charles     |  6200.00 | CJOHNSON |
+-------------+----------+----------+
35 rows in set (0.00 sec)
-- 2. 要求将视图 emp_v1 修改为查询电话号码以‘011’开头的并且邮箱中包含e字符的员工姓名和邮箱, 电话号码:
mysql> ALTER VIEW emp_v1
AS 
SELECT first_name, email, phone_number
FROM emps
WHERE phone_number LIKE '011%' AND email LIKE '%e%';
Query OK, 0 rows affected (0.01 sec)-- 查看视图: 
mysql> SELECT * FROM emp_v1;
+-------------+----------+--------------------+
| first_name  | email    | phone_number       |
+-------------+----------+--------------------+
| John        | JRUSSEL  | 011.44.1344.429268 |
| Karen       | KPARTNER | 011.44.1344.467268 |
| ...         | ...      | ...                |  -- 省略
| Lisa        | LOZER    | 011.44.1343.929268 |
| Elizabeth   | EBATES   | 011.44.1343.529268 |
| Ellen       | EABEL    | 011.44.1644.429267 |
+-------------+----------+--------------------+
16 rows in set (0.00 sec)
-- 3. 向 emp_v1 插入一条记录, 是否可以?
--  先查看emps表结构:
mysql> desc emps;
+-----------------+-------------+------+-----+---------+-------+
| Field           | Type        | Null | Key | Default | Extra |
+-----------------+-------------+------+-----+---------+-------+
| employee_id     | int         | NO   |     | 0       |       |
| first_name      | varchar(20) | YES  |     | NULL    |       |
| last_name       | varchar(25) | NO   |     | NULL    |       |
| email           | varchar(25) | NO   |     | NULL    |       |
| phone_number    | varchar(20) | YES  |     | NULL    |       |
| hire_date       | date        | NO   |     | NULL    |       |  -- 大量非空字段
| job_id          | varchar(10) | NO   |     | NULL    |       |
| salary          | double(8,2) | YES  |     | NULL    |       |
| commission_pct  | double(2,2) | YES  |     | NULL    |       |
| manager_id      | int         | YES  |     | NULL    |       |
| department_id   | int         | YES  |     | NULL    |       |
| department_name | varchar(24) | YES  |     | NULL    |       |
+-----------------+-------------+------+-----+---------+-------+
12 rows in set (0.00 sec)-- 答: 还有非空字段且没有设置默认值, 不能插入数据.
-- 4. 修改emp_v1中员工的工资, 每人涨薪1000
mysql> ALTER VIEW emp_v1 
AS 
SELECT first_name, salary + 1000
FROM emps;
Query OK, 0 rows affected (0.01 sec)-- 查看视图:
mysql> SELECT * FROM emp_v1;
+-------------+---------------+
| first_name  | salary + 1000 |
+-------------+---------------+
| Steven      |      25000.00 |
| Neena       |      18000.00 |
| Lex         |      18000.00 |
| Alexander   |      10000.00 |
| ...         |           ... |
+-------------+---------------+
107 rows in set (0.00 sec)
-- 5. 删除emp_v1中姓名为Christopher的员工:
mysql> SELECT * FROM emp_v1 WHERE first_name = 'Christopher';
+-------------+---------------+
| first_name  | salary + 1000 |
+-------------+---------------+
| Christopher |       9000.00 |
+-------------+---------------+
1 rows in set (0.00 sec)mysql> DELETE FROM emp_v1 WHERE first_name = 'Christopher';
Query OK, 1 row affected (0.00 sec)-- 查看数据:
mysql> SELECT * FROM emp_v1 WHERE first_name = 'Christopher';
Empty set (0.00 sec)
-- 6.  创建视图emp_v2, 要求查询部门的最高工资 高于 12000 的部门id和其最高工资:
mysql> CREATE VIEW emp_v33
AS
SELECT department_id, max(salary) AS `max_sal`
FROM emps
-- WHERE salary > 1200  -- 这样更快
GROUP BY department_id
HAVING max_sal > 12000;
Query OK, 0 rows affected (0.01 sec)-- 查看视图:
mysql> SELECT * FROM emp_v2;
+---------------+-------------+
| department_id | max(salary) |
+---------------+-------------+
|            90 |    24000.00 |
|            80 |    14000.00 |
|            20 |    13000.00 |
+---------------+-------------+
3 rows in set (0.01 sec)
-- 7. 向 emp_v2 中插入一条记录, 是否可以? 肯定不能啊!!! 谁出送分题???
-- 8. 删除刚才的emp_v2 和 emp_v1:
mysql> DROP VIEW IF EXISTS emp_v1, emp_v2;
Query OK, 0 rows affected (0.01 sec)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/302684.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于单片机体温心率检测仪系统设计

**单片机设计介绍, 基于单片机体温心率检测仪系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机体温心率检测仪系统设计是一个综合性的项目,旨在通过单片机及其外围电路实现对人体体温和心…

850. Dijkstra求最短路 II

850. Dijkstra求最短路 II 代码&#xff1a; #include<algorithm> #include<iostream> #include<cstring> #include<queue> #include<cmath>using namespace std; //用pair存储编号和距离 typedef pair<int,int> PII;int n,m; const int …

HarmonyOS 应用开发-ArkUI(ets)仿“腾讯新闻”APP

一、效果演示 1、新闻列表页 2、新闻详情页、图片展示页 3、视频页 4、动态页 二、 流程图 –本来自定义了视频的控制栏的&#xff0c;但是发现VideoController()控制器的bug会导致控制器失效&#xff0c;所以没继续做。视频页先不搞了。 三、文件组织&#xff08;“我的页面…

openharmony launcher 调研笔记(03)UI 数据装配

最近在看launcher&#xff0c;把自己调研的点做个笔记&#xff0c;持续修改更新中&#xff0c;个人笔记酌情参考。 桌面上半部分包含父子逻辑&#xff1a; Column() { PageDesktopLayout(); } PageDesktopLayout->GridSwiper->Swiper->SwiperPage 1.PageDe…

jmeter压测websocket协议

一、jmeter 安装websocket插件 1、选项--插件管理 2、搜索WebSocket Samplers by Peter Doornbosch插件 进行安装 3、 重启 jmeter 二、jmeter压测websocket协议实战 2.1、以网站为例&#xff1a; websocket在线测试 1、断开连接 2、打开F12&#xff0c;查看WS数据 3、…

Microsoft Visio 参与者 [actor] - 人的形状图标

Microsoft Visio 参与者 [actor] - 人的形状图标 1. 更多形状 -> 搜索形状2. 参与者References 1. 更多形状 -> 搜索形状 2. 参与者 References [1] Yongqiang Cheng, https://yongqiang.blog.csdn.net/

LeetCode-139. 单词拆分【字典树 记忆化搜索 数组 哈希表 字符串 动态规划】

LeetCode-139. 单词拆分【字典树 记忆化搜索 数组 哈希表 字符串 动态规划】 题目描述&#xff1a;解题思路一&#xff1a;Python动态规划五部曲&#xff1a;定推初遍举【先遍历背包 后遍历物品】必须是排列解题思路二&#xff1a;Python动态规划版本二解题思路三&#xff1a;回…

电脑打开游戏的时候提示缺少.dll文件?照着这个来就行。

前言 小白曾经也是一个很喜欢玩游戏的人&#xff0c;但那只是曾经。那时候宿舍里一共6个人&#xff0c;都是比较喜欢玩游戏的小伙子。 话题好像偏了…… 有些小伙伴下载玩游戏之后&#xff0c;高高兴兴地想要开始玩。结果游戏根本没办法运行&#xff0c;可恶&#xff01;这该…

数据库-root密码丢失的重置方案(win11环境)

当在windows系统中安装的mysql由于操作不当&#xff0c;或者密码遗忘&#xff0c;今天测试了一下&#xff0c;可以用以下方法重置root的密码。 mysqlwindows环境root密码重置问题 在win10/11环境下mysql8密码遗忘后的重置密码方案。 停止mysql服务 查找windows中的mysql服务名称…

达梦备份与恢复

达梦备份与恢复 基础环境 操作系统&#xff1a;Red Hat Enterprise Linux Server release 7.9 (Maipo) 数据库版本&#xff1a;DM Database Server 64 V8 架构&#xff1a;单实例1 设置bak_path路径 --创建备份文件存放目录 su - dmdba mkdir -p /dm8/backup--修改dm.ini 文件…

FreeRTOS源码精简

理解堆的概念和栈的概念 堆 栈 精简FreeRTOS源码 这个源文件的工程是使用KEIL4进行编写的这里我们将它更新为KEIL5 更新之后关闭并重启工程 上面的Commom这个文件实际上是不能删除的&#xff0c;删除会出现很多的错误但是可以对这个文件进行精简 编译后通过

file_get_contents(‘php://input‘); 这个postman要如何传参

在 Postman 中传递参数给 file_get_contents(php://input); 是通过请求的 Body 部分来实现的。使用 Postman 进行 API 接口测试时&#xff0c;可以按照以下步骤来传递参数&#xff1a; 打开 Postman 并创建一个新的请求。在请求的 URL 地址栏输入你的 API 地址。选择请求方法为…

使用Java流API构建树形结构数据

简介&#xff1a; 在实际开发中&#xff0c;构建树状层次结构是常见需求&#xff0c;如组织架构、目录结构或菜单系统。本教案通过解析给定的Java代码&#xff0c;展示如何使用Java 8 Stream API将扁平化的菜单数据转换为具有层级关系的树形结构。 1. 核心类定义 - Menu Data…

阿里面试题二

实在是太长了 重新开一篇吧 dubbo 服务暴露 Dubbo——服务调用、服务暴露、服务引用过程 - 简书 这两篇文章写的是极好 我现在查得资源强的可怕朋友们 服务降级 MockClusterInvoker 负载均衡策略 容错机制在哪里实现的源码 通信 NIO、BIO区别&#xff0c;NIO解决了什么…

layui后台框架,将左侧功能栏目 集中到一个页面,通过上面的tab切换 在iframe加载对应页面

实现上面的 功能效果。 1 html代码 <form class"layui-form layui-form-pane" action""><div class"layui-tab" lay-filter"demo"><ul class"layui-tab-title"><li id"a0" class"lay…

联想电脑VMware虚拟机VT开启虚拟化

以联想电脑为例。 关机重启&#xff0c; 有的电脑是按F2&#xff0c; 有的是按fnF2 进入BIOS&#xff0c;左右键&#xff0c;选择Configuration&#xff0c; 再上下键选择 Intel Virtual Technology 按回车键&#xff0c;再按上下键选择 Enable &#xff0c;回车确认。 按fn…

用友NC Cloud importhttpscer 任意文件上传漏洞复现

0x01 产品简介 用友 NC Cloud 是一种商业级的企业资源规划云平台,为企业提供全面的管理解决方案,包括财务管理、采购管理、销售管理、人力资源管理等功能,基于云原生架构,深度应用新一代数字技术,打造开放、 互联、融合、智能的一体化云平台,支持公有云、混合云、专属云…

ChatGPT/GPT4科研应用与绘图技术及论文写作

2023年随着OpenAI开发者大会的召开&#xff0c;最重磅更新当属GPTs&#xff0c;多模态API&#xff0c;未来自定义专属的GPT。微软创始人比尔盖茨称ChatGPT的出现有着重大历史意义&#xff0c;不亚于互联网和个人电脑的问世。360创始人周鸿祎认为未来各行各业如果不能搭上这班车…

LeetCode-322. 零钱兑换【广度优先搜索 数组 动态规划】

LeetCode-322. 零钱兑换【广度优先搜索 数组 动态规划】 题目描述&#xff1a;解题思路一&#xff1a;Python动态规划五部曲&#xff1a;定推初遍举【先遍历物品 后遍历背包】解题思路二&#xff1a;Python动态规划五部曲&#xff1a;定推初遍举【先遍历背包 后遍历物品】解题思…

自动驾驶中的多目标跟踪_第三篇

自动驾驶中的多目标跟踪:第三篇 附赠自动驾驶学习资料和量产经验&#xff1a;链接 在前一节&#xff0c;我们回顾了贝叶斯滤波&#xff0c;并给出了线性高斯条件下的闭式解–卡尔曼滤波。在这一节&#xff0c;我们来讨论杂波背景下的单目标滤波问题。 模型 &#xff08;三&…