引言

视图(View)是虚拟表,本质是存储的SELECT语句。可以像表一样查询,但不实际存储数据。


一、视图基础

1.1 什么是视图?

视图是一个虚拟表,由查询结果组成。

特点

  • 不存储数据(只存储定义)
  • 基于基础表动态生成
  • 可以像表一样查询
-- 创建视图
CREATE VIEW view_name AS
SELECT column1, column2
FROM table_name
WHERE condition;

-- 查询视图
SELECT * FROM view_name;

1.2 视图的作用

  1. 简化复杂查询:封装复杂SQL
  2. 提高安全性:隐藏敏感字段
  3. 逻辑数据独立:修改表结构不影响应用
  4. 权限控制:只授予视图权限

二、创建视图

2.1 基础语法

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

2.2 简单视图

-- 创建用户信息视图(隐藏敏感字段)
CREATE VIEW v_user_info AS
SELECT id, name, email, created_at
FROM users;

-- 查询视图
SELECT * FROM v_user_info;

2.3 复杂视图

-- 用户订单统计视图
CREATE VIEW v_user_order_stats AS
SELECT u.id, u.name,
       COUNT(o.id) AS order_count,
       IFNULL(SUM(o.amount), 0) AS total_amount,
       ROUND(AVG(o.amount), 2) AS avg_amount
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.id, u.name;

-- 使用视图
SELECT * FROM v_user_order_stats WHERE order_count > 5;

2.4 带条件的视图

-- 只显示有效商品
CREATE VIEW v_active_products AS
SELECT id, name, price, stock
FROM products
WHERE status = 1 AND stock > 0;

三、查看和管理视图

3.1 查看视图列表

-- 查看所有视图
SHOW FULL TABLES WHERE Table_type = 'VIEW';

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

3.2 修改视图

-- 方式1:CREATE OR REPLACE
CREATE OR REPLACE VIEW v_user_info AS
SELECT id, name, email, phone, created_at
FROM users;

-- 方式2:ALTER VIEW
ALTER VIEW v_user_info AS
SELECT id, name, email, phone, created_at
FROM users;

3.3 删除视图

DROP VIEW IF EXISTS v_user_info;

四、视图的更新

4.1 可更新视图

满足以下条件的视图可以更新:

  • 没有聚合函数(SUM、COUNT等)
  • 没有DISTINCT
  • 没有GROUP BY
  • 没有HAVING
  • 没有UNION
-- 可更新视图
CREATE VIEW v_users AS
SELECT id, name, email FROM users;

-- 通过视图更新数据
UPDATE v_users SET name = '张三' WHERE id = 1;
INSERT INTO v_users (name, email) VALUES ('李四', 'lisi@example.com');
DELETE FROM v_users WHERE id = 2;

4.2 WITH CHECK OPTION

确保通过视图插入/更新的数据符合视图的WHERE条件。

-- 创建只能查看价格>1000商品的视图
CREATE VIEW v_expensive_products AS
SELECT * FROM products WHERE price > 1000
WITH CHECK OPTION;

-- ✅ 成功
INSERT INTO v_expensive_products (name, price) VALUES ('商品A', 2000);

-- ❌ 失败:不符合WHERE条件
INSERT INTO v_expensive_products (name, price) VALUES ('商品B', 500);

五、视图的限制

5.1 不可更新的视图

-- 包含聚合函数
CREATE VIEW v_category_stats AS
SELECT category, COUNT(*) AS cnt
FROM products
GROUP BY category;
-- 不能UPDATE/INSERT/DELETE

-- 包含DISTINCT
CREATE VIEW v_unique_categories AS
SELECT DISTINCT category FROM products;
-- 不能UPDATE/INSERT/DELETE

-- 包含JOIN
CREATE VIEW v_order_details AS
SELECT o.*, u.name
FROM orders o
INNER JOIN users u ON o.user_id = u.id;
-- 通常不能UPDATE/INSERT/DELETE(视具体情况)

5.2 性能问题

-- ❌ 差:视图嵌套
CREATE VIEW v1 AS SELECT * FROM products WHERE price > 1000;
CREATE VIEW v2 AS SELECT * FROM v1 WHERE stock > 10;
CREATE VIEW v3 AS SELECT * FROM v2 WHERE category = '手机';

-- ✅ 好:合并为一个查询
CREATE VIEW v_filtered_products AS
SELECT * FROM products
WHERE price > 1000 AND stock > 10 AND category = '手机';

六、实战案例

案例1:隐藏敏感信息

-- 用户表包含密码、身份证等敏感信息
CREATE VIEW v_public_user_info AS
SELECT id, name, email, created_at
FROM users;

-- 应用只需查询视图
SELECT * FROM v_public_user_info;

案例2:简化复杂查询

-- 封装复杂的统计查询
CREATE VIEW v_monthly_sales AS
SELECT DATE_FORMAT(created_at, '%Y-%m') AS month,
       COUNT(*) AS order_count,
       SUM(amount) AS total_sales,
       ROUND(AVG(amount), 2) AS avg_order_value
FROM orders
WHERE status = 'completed'
GROUP BY DATE_FORMAT(created_at, '%Y-%m');

-- 应用层简单查询
SELECT * FROM v_monthly_sales WHERE month >= '2024-01';

案例3:权限控制

-- 不同部门看到不同数据
CREATE VIEW v_sales_dept AS
SELECT * FROM orders WHERE dept = 'sales';

CREATE VIEW v_tech_dept AS
SELECT * FROM orders WHERE dept = 'tech';

-- 授予不同权限
GRANT SELECT ON v_sales_dept TO 'sales_user'@'%';
GRANT SELECT ON v_tech_dept TO 'tech_user'@'%';

七、视图 vs 临时表 vs 子查询

对比项视图临时表子查询
存储数据
可重用会话内
性能取决于查询取决于查询
维护性

选择建议

  • 需要重用:视图
  • 中间结果复杂:临时表
  • 一次性查询:子查询

八、总结

核心要点

  1. 视图:虚拟表,存储查询定义
  2. 作用:简化查询、提高安全性、权限控制
  3. 可更新:无聚合、DISTINCT、GROUP BY的简单视图
  4. WITH CHECK OPTION:保证更新符合WHERE条件
  5. 限制:性能依赖基础表,避免嵌套视图

记忆口诀

视图虚拟表一张,存储定义不存量,
简化查询提安全,权限控制把关良。
可更新视图条件,无聚合无分组样,
CHECK OPTION保条件,实战案例记心房。

本文字数:约2,400字 难度等级:⭐⭐(SQL进阶)