Skip to content

视图

视图(View)是一个虚拟表,其内容由查询定义。本章将介绍MySQL视图的创建、修改和使用方法。

视图概述

sql
/*
 * 视图的特点:
 * 1. 虚拟表,不存储实际数据
 * 2. 数据来自定义视图的查询
 * 3. 简化复杂查询
 * 4. 提供数据安全性
 * 5. 数据独立性
 * 
 * 视图的优点:
 * 1. 简化复杂查询
 * 2. 保护敏感数据
 * 3. 提供向后兼容性
 * 4. 重用SQL语句
 * 
 * 视图的限制:
 * 1. 不能创建临时表上的视图
 * 2. 不能在视图上创建触发器
 * 3. 某些视图不可更新
 */

创建视图

基本语法

sql
-- 创建视图的基本语法
/*
CREATE [OR REPLACE] [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]
VIEW 视图名 [(列名列表)]
AS 查询语句
[WITH [CASCADED | LOCAL] CHECK OPTION];
*/

-- 准备示例数据
USE company;

-- 创建简单视图
CREATE VIEW v_employees AS
SELECT id, name, department_id, salary
FROM employees;

-- 查询视图
SELECT * FROM v_employees;

-- 创建带列别名的视图
CREATE VIEW v_employee_info (员工ID, 姓名, 部门ID, 工资) AS
SELECT id, name, department_id, salary
FROM employees;

SELECT * FROM v_employee_info;

复杂视图

sql
-- 创建多表连接视图
CREATE VIEW v_employee_dept AS
SELECT 
    e.id,
    e.name AS employee_name,
    d.name AS department_name,
    e.salary
FROM employees e
LEFT JOIN departments d ON e.department_id = d.id;

SELECT * FROM v_employee_dept;

-- 创建聚合视图
CREATE VIEW v_dept_stats AS
SELECT 
    d.name AS department_name,
    COUNT(e.id) AS employee_count,
    AVG(e.salary) AS avg_salary,
    MAX(e.salary) AS max_salary,
    MIN(e.salary) AS min_salary
FROM departments d
LEFT JOIN employees e ON d.id = e.department_id
GROUP BY d.id, d.name;

SELECT * FROM v_dept_stats;

-- 创建子查询视图
CREATE VIEW v_high_salary_employees AS
SELECT 
    e.name,
    e.salary,
    e.department_id
FROM employees e
WHERE e.salary > (
    SELECT AVG(salary) FROM employees
);

SELECT * FROM v_high_salary_employees;

OR REPLACE

sql
-- 使用OR REPLACE创建或替换视图
CREATE OR REPLACE VIEW v_employees AS
SELECT 
    id, 
    name, 
    department_id, 
    salary,
    hire_date
FROM employees;

-- 等价于先删除再创建
DROP VIEW IF EXISTS v_employees;
CREATE VIEW v_employees AS
SELECT id, name, department_id, salary, hire_date
FROM employees;

查看视图

sql
-- 查看数据库中的视图
SHOW FULL TABLES WHERE TABLE_TYPE = 'VIEW';

-- 查看视图结构
DESC v_employees;

-- 查看视图定义
SHOW CREATE VIEW v_employees;

-- 从information_schema查询视图
SELECT 
    TABLE_NAME,
    VIEW_DEFINITION,
    CHECK_OPTION,
    IS_UPDATABLE
FROM information_schema.VIEWS
WHERE TABLE_SCHEMA = DATABASE();

修改视图

sql
-- 使用ALTER VIEW修改视图
ALTER VIEW v_employees AS
SELECT 
    id, 
    name, 
    department_id, 
    salary,
    hire_date,
    status
FROM employees;

-- 或使用CREATE OR REPLACE
CREATE OR REPLACE VIEW v_employees AS
SELECT 
    id, 
    name, 
    department_id, 
    salary
FROM employees
WHERE status = 'active';

可更新视图

sql
/*
 * 可更新视图的条件:
 * 1. 没有聚合函数(SUM、COUNT等)
 * 2. 没有DISTINCT
 * 3. 没有GROUP BY、HAVING
 * 4. 没有UNION
 * 5. 没有子查询
 * 6. 视图中的列来自单个表
 */

-- 创建可更新视图
CREATE VIEW v_active_employees AS
SELECT id, name, salary, department_id
FROM employees
WHERE status = 'active';

-- 通过视图插入数据
INSERT INTO v_active_employees (name, salary, department_id)
VALUES ('新员工', 12000, 1);

-- 通过视图更新数据
UPDATE v_active_employees 
SET salary = 13000 
WHERE name = '新员工';

-- 通过视图删除数据
DELETE FROM v_active_employees WHERE name = '新员工';

-- 使用WITH CHECK OPTION
CREATE VIEW v_tech_employees AS
SELECT id, name, salary, department_id
FROM employees
WHERE department_id = 1
WITH CHECK OPTION;

-- 插入数据时检查条件
INSERT INTO v_tech_employees (name, salary, department_id)
VALUES ('技术员', 15000, 1);  -- 成功

-- INSERT INTO v_tech_employees (name, salary, department_id)
-- VALUES ('销售员', 15000, 2);  -- 失败,不满足department_id = 1

删除视图

sql
-- 删除视图
DROP VIEW v_employees;

-- 删除多个视图
DROP VIEW v_employee_dept, v_dept_stats;

-- 安全删除(如果存在)
DROP VIEW IF EXISTS v_employees;

视图应用场景

sql
-- 场景1:简化复杂查询
CREATE VIEW v_order_details AS
SELECT 
    o.order_no,
    u.username,
    p.name AS product_name,
    oi.quantity,
    oi.price,
    oi.quantity * oi.price AS subtotal
FROM orders o
JOIN users u ON o.user_id = u.id
JOIN order_items oi ON o.id = oi.order_id
JOIN products p ON oi.product_id = p.id;

-- 使用视图简化查询
SELECT * FROM v_order_details WHERE username = 'user1';

-- 场景2:数据安全(隐藏敏感列)
CREATE VIEW v_public_employees AS
SELECT id, name, department_id
FROM employees;
-- 不暴露salary等敏感信息

-- 场景3:数据格式化
CREATE VIEW v_formatted_data AS
SELECT 
    id,
    name,
    DATE_FORMAT(hire_date, '%Y年%m月%d日') AS 入职日期,
    FORMAT(salary, 2) AS 工资
FROM employees;

-- 场景4:业务逻辑封装
CREATE VIEW v_monthly_report AS
SELECT 
    DATE_FORMAT(hire_date, '%Y-%m') AS 月份,
    COUNT(*) AS 入职人数,
    SUM(salary) AS 工资总额
FROM employees
GROUP BY DATE_FORMAT(hire_date, '%Y-%m');

视图算法

sql
/*
 * 视图算法:
 * 
 * MERGE:将视图定义的SQL与查询SQL合并
 *        - 性能好
 *        - 可以使用索引
 * 
 * TEMPTABLE:将视图结果存入临时表
 *            - 性能较差
 *            - 不能使用视图上的索引
 * 
 * UNDEFINED:MySQL自动选择(默认)
 */

-- 指定算法创建视图
CREATE ALGORITHM = MERGE VIEW v_merge_test AS
SELECT id, name FROM employees;

CREATE ALGORITHM = TEMPTABLE VIEW v_temptable_test AS
SELECT id, name FROM employees GROUP BY department_id;

本章小结

本章学习了:

  • 视图概念:虚拟表,不存储数据
  • 创建视图:CREATE VIEW语法
  • 查看视图:DESC、SHOW CREATE VIEW
  • 修改视图:ALTER VIEW、OR REPLACE
  • 可更新视图:通过视图操作数据
  • 视图应用:简化查询、数据安全、格式化

下一章,我们将学习存储过程,了解如何创建和使用存储过程。