视图 #

一、视图概述 #

1.1 视图概念 #

text
视图类型
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   普通视图:                                                 │
│   ├── 虚拟表,不存储数据                                   │
│   ├── 每次查询时执行定义的SQL                              │
│   └── 简化复杂查询                                         │
│                                                             │
│   物化视图:                                                 │
│   ├── 存储查询结果                                         │
│   ├── 需要手动刷新                                         │
│   └── 提高查询性能                                         │
│                                                             │
│   视图优点:                                                 │
│   ├── 简化复杂查询                                         │
│   ├── 提供数据抽象层                                       │
│   ├── 实现数据安全                                         │
│   └── 保持数据一致性                                       │
│                                                             │
└─────────────────────────────────────────────────────────────┘

二、创建视图 #

2.1 基本语法 #

sql
-- 创建视图
CREATE VIEW active_users AS
SELECT id, name, email
FROM users
WHERE status = 'active';

-- 使用视图
SELECT * FROM active_users;

-- 创建带列名的视图
CREATE VIEW user_summary (user_id, user_name, total_orders)
AS
SELECT 
    u.id,
    u.name,
    COUNT(o.id)
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.id, u.name;

SELECT * FROM user_summary;

2.2 复杂视图 #

sql
-- 多表连接视图
CREATE VIEW order_details AS
SELECT 
    o.id AS order_id,
    o.order_no,
    u.name AS customer_name,
    u.email,
    o.amount,
    o.status,
    o.created_at
FROM orders o
JOIN users u ON o.user_id = u.id;

-- 聚合视图
CREATE VIEW sales_summary AS
SELECT 
    DATE(created_at) AS sale_date,
    COUNT(*) AS order_count,
    SUM(amount) AS total_amount,
    AVG(amount) AS avg_amount
FROM orders
GROUP BY DATE(created_at);

-- 使用窗口函数的视图
CREATE VIEW ranked_products AS
SELECT 
    product_name,
    category,
    price,
    RANK() OVER (PARTITION BY category ORDER BY price DESC) AS price_rank
FROM products;

2.3 视图选项 #

sql
-- OR REPLACE: 替换已存在的视图
CREATE OR REPLACE VIEW active_users AS
SELECT id, name, email, status
FROM users
WHERE status = 'active';

-- TEMPORARY: 创建临时视图
CREATE TEMP VIEW recent_orders AS
SELECT * FROM orders
WHERE created_at > NOW() - INTERVAL '7 days';

-- CHECK OPTION: 更新时检查条件
CREATE VIEW active_users_check AS
SELECT * FROM users WHERE status = 'active'
WITH CHECK OPTION;

-- 更新时必须满足 status = 'active'
UPDATE active_users_check SET status = 'inactive' WHERE id = 1;
-- 会报错,因为违反视图条件

三、修改视图 #

3.1 修改视图定义 #

sql
-- 使用 CREATE OR REPLACE
CREATE OR REPLACE VIEW active_users AS
SELECT id, name, email, created_at
FROM users
WHERE status = 'active';

-- 使用 ALTER VIEW
ALTER VIEW active_users RENAME TO v_active_users;

-- 删除并重建
DROP VIEW active_users;
CREATE VIEW active_users AS
SELECT id, name, email, phone
FROM users
WHERE status = 'active';

3.2 视图依赖 #

sql
-- 查看视图依赖
SELECT 
    dependent_view.relname AS view_name,
    source_table.relname AS source_table
FROM pg_depend
JOIN pg_class dependent_view ON pg_depend.objid = dependent_view.oid
JOIN pg_class source_table ON pg_depend.refobjid = source_table.oid
WHERE dependent_view.relkind = 'v';

-- 删除依赖视图
DROP VIEW order_details CASCADE;  -- 同时删除依赖此视图的对象

四、可更新视图 #

4.1 可更新视图条件 #

text
可更新视图条件
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   视图可以更新,需要满足:                                   │
│   ├── FROM 子句只有一个表                                  │
│   ├── 不包含聚合函数                                       │
│   ├── 不包含 DISTINCT                                      │
│   ├── 不包含 GROUP BY                                      │
│   ├── 不包含 HAVING                                       │
│   ├── 不包含 UNION/INTERSECT/EXCEPT                        │
│   └── 不包含子查询                                         │
│                                                             │
│   简单视图通常可以更新                                      │
│   复杂视图通常只能读取                                      │
│                                                             │
└─────────────────────────────────────────────────────────────┘

4.2 更新视图示例 #

sql
-- 可更新视图
CREATE VIEW user_emails AS
SELECT id, name, email
FROM users;

-- 通过视图插入
INSERT INTO user_emails (id, name, email)
VALUES (gen_random_uuid(), 'Test', 'test@example.com');

-- 通过视图更新
UPDATE user_emails
SET email = 'new@example.com'
WHERE name = 'Test';

-- 通过视图删除
DELETE FROM user_emails WHERE name = 'Test';

五、物化视图 #

5.1 创建物化视图 #

sql
-- 创建物化视图
CREATE MATERIALIZED VIEW sales_report AS
SELECT 
    DATE(created_at) AS sale_date,
    COUNT(*) AS order_count,
    SUM(amount) AS total_amount
FROM orders
GROUP BY DATE(created_at);

-- 查询物化视图
SELECT * FROM sales_report;

-- 刷新物化视图
REFRESH MATERIALIZED VIEW sales_report;

-- 带数据的物化视图
CREATE MATERIALIZED VIEW product_sales AS
SELECT 
    p.product_name,
    COUNT(oi.id) AS sale_count,
    SUM(oi.quantity * oi.price) AS total_revenue
FROM products p
LEFT JOIN order_items oi ON p.id = oi.product_id
GROUP BY p.id, p.product_name
WITH DATA;  -- 立即填充数据

5.2 管理物化视图 #

sql
-- 刷新物化视图
REFRESH MATERIALIZED VIEW sales_report;

-- 删除数据 (保留定义)
REFRESH MATERIALIZED VIEW sales_report WITH NO DATA;

-- 查看物化视图内容
SELECT * FROM sales_report;

-- 删除物化视图
DROP MATERIALIZED VIEW sales_report;

5.3 物化视图使用场景 #

text
物化视图使用场景
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   适用场景:                                                 │
│   ├── 复杂聚合查询                                         │
│   ├── 数据仓库报表                                         │
│   ├── 实时性要求不高                                       │
│   └── 查询频繁但数据变化慢                                 │
│                                                             │
│   不适用场景:                                               │
│   ├── 需要实时数据                                         │
│   ├── 数据频繁变化                                         │
│   └── 存储空间有限                                         │
│                                                             │
│   刷新策略:                                                 │
│   ├── 定时刷新 (cron job)                                  │
│   ├── 事件触发刷新                                         │
│   └── 手动刷新                                             │
│                                                             │
└─────────────────────────────────────────────────────────────┘

六、视图管理 #

6.1 查看视图 #

sql
-- 查看所有视图
SELECT * FROM information_schema.views
WHERE table_schema = 'public';

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

-- 查看视图列
SELECT * FROM information_schema.columns
WHERE table_name = 'active_users'
  AND table_schema = 'public';

-- 查看物化视图
SELECT * FROM pg_class WHERE relkind = 'm';

6.2 视图权限 #

sql
-- 授予视图查询权限
GRANT SELECT ON active_users TO readonly_user;

-- 授予视图所有权限
GRANT ALL ON active_users TO admin_user;

-- 回收权限
REVOKE SELECT ON active_users FROM readonly_user;

七、视图最佳实践 #

7.1 设计原则 #

text
视图设计原则
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   1. 视图命名规范                                           │
│      ├── 使用 v_ 前缀                                      │
│      └── 名称清晰表达用途                                  │
│                                                             │
│   2. 视图职责单一                                           │
│      ├── 每个视图一个目的                                  │
│      └── 避免过于复杂                                      │
│                                                             │
│   3. 性能考虑                                               │
│      ├── 视图不存储数据                                    │
│      ├── 复杂视图影响性能                                  │
│      └── 考虑使用物化视图                                  │
│                                                             │
│   4. 安全考虑                                               │
│      ├── 限制列访问                                        │
│      ├── 限制行访问                                        │
│      └── 使用权限控制                                      │
│                                                             │
└─────────────────────────────────────────────────────────────┘

7.2 使用示例 #

sql
-- 数据安全视图
CREATE VIEW v_user_public AS
SELECT id, name
FROM users;

-- 只暴露公开信息

-- 业务逻辑封装视图
CREATE VIEW v_order_summary AS
SELECT 
    o.id,
    o.order_no,
    u.name AS customer,
    o.amount,
    CASE o.status
        WHEN 'pending' THEN '待处理'
        WHEN 'paid' THEN '已支付'
        WHEN 'shipped' THEN '已发货'
        WHEN 'completed' THEN '已完成'
        ELSE '未知'
    END AS status_text
FROM orders o
JOIN users u ON o.user_id = u.id;

-- 报表视图
CREATE VIEW v_daily_sales AS
SELECT 
    DATE(created_at) AS sale_date,
    COUNT(*) AS orders,
    SUM(amount) AS revenue,
    COUNT(DISTINCT user_id) AS customers
FROM orders
WHERE status = 'completed'
GROUP BY DATE(created_at);

八、总结 #

视图要点:

类型 说明
普通视图 虚拟表,不存储数据
可更新视图 可以通过视图修改数据
物化视图 存储查询结果
临时视图 会话级别,自动删除
安全视图 限制数据访问

下一步,让我们学习序列!

最后更新:2026-03-27