视图
视图(View)是一种虚拟表,它基于 SQL 查询语句的结果集。视图本身不存储数据,而是在查询时动态生成。视图可以简化复杂查询、保护数据安全、提供数据独立性。
视图概述
什么是视图
视图是一张虚拟表,它的内容由 SELECT 查询定义。视图不存储实际数据,每次查询视图时,数据库会执行视图定义的查询语句。
视图的优点
| 优点 | 说明 |
|---|---|
| 简化查询 | 封装复杂查询,简化使用 |
| 数据安全 | 可以隐藏敏感字段 |
| 数据独立 | 修改底层表结构不影响应用 |
| 重用性 | 一次定义,多次使用 |
视图的缺点
| 缺点 | 说明 |
|---|---|
| 性能开销 | 每次查询都要执行定义的 SQL |
| 更新限制 | 复杂视图可能无法更新 |
| 调试困难 | 视图嵌套时难以定位问题 |
创建视图
基本语法
sql
CREATE VIEW 视图名 AS
SELECT 列名
FROM 表名
WHERE 条件;创建简单视图
sql
-- 创建高于平均身高的球员视图
CREATE VIEW player_above_avg_height AS
SELECT player_id, player_name, height
FROM player
WHERE height > (SELECT AVG(height) FROM player);
-- 使用视图
SELECT * FROM player_above_avg_height;创建带别名的视图
sql
CREATE VIEW player_info AS
SELECT
player_id AS id,
player_name AS name,
height AS h
FROM player;创建多表连接视图
sql
CREATE VIEW player_team_info AS
SELECT
p.player_name,
p.height,
t.team_name
FROM player p
JOIN team t ON p.team_id = t.team_id;创建计算字段视图
sql
CREATE VIEW player_score_detail AS
SELECT
game_id,
player_id,
(shoot_hits - shoot_3_hits) * 2 AS two_points,
shoot_3_hits * 3 AS three_points,
shoot_p_hits AS free_throws,
score AS total_points
FROM player_score;修改视图
ALTER VIEW
sql
ALTER VIEW player_above_avg_height AS
SELECT
player_id,
player_name,
height,
team_id
FROM player
WHERE height > (SELECT AVG(height) FROM player);CREATE OR REPLACE VIEW
sql
-- 如果视图存在则替换,不存在则创建
CREATE OR REPLACE VIEW player_above_avg_height AS
SELECT player_id, player_name, height
FROM player
WHERE height > (SELECT AVG(height) FROM player);删除视图
基本语法
sql
DROP VIEW 视图名;
-- 如果存在则删除
DROP VIEW IF EXISTS player_above_avg_height;删除多个视图
sql
DROP VIEW view1, view2, view3;嵌套视图
视图可以基于其他视图创建:
sql
-- 基础视图
CREATE VIEW player_above_avg_height AS
SELECT player_id, player_name, height
FROM player
WHERE height > (SELECT AVG(height) FROM player);
-- 嵌套视图
CREATE VIEW player_above_above_avg_height AS
SELECT player_id, player_name, height
FROM player
WHERE height > (SELECT AVG(height) FROM player_above_avg_height);注意:嵌套视图会增加查询复杂度,影响性能,应避免过深嵌套。
可更新视图
可更新视图条件
视图满足以下条件时可以执行 INSERT、UPDATE、DELETE:
- 没有聚合函数(SUM、COUNT、AVG 等)
- 没有 DISTINCT
- 没有 GROUP BY、HAVING
- 没有 UNION、UNION ALL
- 没有子查询
- 只引用一个表
更新视图示例
sql
-- 创建可更新视图
CREATE VIEW student_view AS
SELECT id, name, score FROM students;
-- 通过视图更新数据
UPDATE student_view SET score = 90 WHERE id = 1;
-- 通过视图插入数据
INSERT INTO student_view (name, score) VALUES ('新学生', 80);
-- 通过视图删除数据
DELETE FROM student_view WHERE id = 1;WITH CHECK OPTION
确保通过视图修改的数据仍然满足视图条件:
sql
CREATE VIEW high_score_students AS
SELECT id, name, score
FROM students
WHERE score >= 80
WITH CHECK OPTION;
-- 尝试将分数改为 70(会失败)
UPDATE high_score_students SET score = 70 WHERE id = 1;
-- Error: CHECK OPTION failed视图应用场景
1. 简化复杂查询
sql
-- 创建复杂查询视图
CREATE VIEW player_height_grades AS
SELECT
p.player_name,
p.height,
h.height_level
FROM player p
JOIN height_grades h
ON p.height BETWEEN h.height_lowest AND h.height_highest;
-- 简化查询
SELECT * FROM player_height_grades
WHERE height >= 1.90 AND height <= 2.08;2. 数据格式化
sql
-- 格式化输出
CREATE VIEW player_team_formatted AS
SELECT
CONCAT(p.player_name, '(', t.team_name, ')') AS player_info
FROM player p
JOIN team t ON p.team_id = t.team_id;
-- 使用
SELECT * FROM player_team_formatted;
-- 结果:韦恩-艾灵顿(底特律活塞)3. 数据安全
sql
-- 隐藏敏感字段
CREATE VIEW employee_public AS
SELECT id, name, department, position
FROM employee;
-- 不包含 salary、id_card 等敏感字段
-- 授权访问视图而非原表
GRANT SELECT ON employee_public TO public_user;4. 数据统计
sql
-- 统计视图
CREATE VIEW department_stats AS
SELECT
department,
COUNT(*) AS employee_count,
AVG(salary) AS avg_salary,
MAX(salary) AS max_salary,
MIN(salary) AS min_salary
FROM employee
GROUP BY department;
-- 使用
SELECT * FROM department_stats;5. 历史数据
sql
-- 创建历史数据视图
CREATE VIEW orders_2024 AS
SELECT * FROM orders
WHERE YEAR(order_date) = 2024;视图性能优化
1. 避免嵌套视图
sql
-- 差:嵌套视图
CREATE VIEW v1 AS SELECT * FROM table1;
CREATE VIEW v2 AS SELECT * FROM v1;
CREATE VIEW v3 AS SELECT * FROM v2;
-- 好:直接定义
CREATE VIEW v3 AS SELECT * FROM table1;2. 使用索引
sql
-- 确保视图查询的表有适当索引
CREATE INDEX idx_player_height ON player(height);3. 物化视图(MySQL 不原生支持)
sql
-- 使用表模拟物化视图
CREATE TABLE mv_player_stats AS
SELECT
team_id,
COUNT(*) AS player_count,
AVG(height) AS avg_height
FROM player
GROUP BY team_id;
-- 定期刷新
TRUNCATE TABLE mv_player_stats;
INSERT INTO mv_player_stats
SELECT team_id, COUNT(*), AVG(height)
FROM player
GROUP BY team_id;视图管理
查看视图定义
sql
-- 查看视图结构
DESCRIBE view_name;
DESC view_name;
-- 查看视图创建语句
SHOW CREATE VIEW view_name;
-- 从 information_schema 查询
SELECT * FROM information_schema.VIEWS
WHERE TABLE_NAME = 'view_name';查看所有视图
sql
SELECT TABLE_NAME, TABLE_TYPE
FROM information_schema.TABLES
WHERE TABLE_TYPE = 'VIEW';总结
视图操作
| 操作 | 语法 |
|---|---|
| 创建 | CREATE VIEW 视图名 AS SELECT ... |
| 修改 | ALTER VIEW 视图名 AS SELECT ... |
| 删除 | DROP VIEW 视图名 |
| 查看 | SHOW CREATE VIEW 视图名 |
视图特点
| 特点 | 说明 |
|---|---|
| 虚拟表 | 不存储实际数据 |
| 动态生成 | 查询时执行定义的 SQL |
| 可更新 | 简单视图支持 DML 操作 |
| 安全性 | 可隐藏敏感字段 |
最佳实践
- 简化复杂查询:将常用复杂查询封装为视图
- 控制嵌套深度:避免视图嵌套视图
- 合理使用索引:确保底层表的查询效率
- 考虑性能:频繁使用的复杂查询考虑使用物化表
- 权限控制:通过视图限制数据访问