Skip to content

PostgreSQL - 视图

在 PostgreSQL 中,视图(View)是一个存储的 SELECT 查询,它充当虚拟表。它本身不存储数据,而是从一个或多个底层基表派生其数据。视图通常用于简化复杂查询、强制实施安全性以及提供一致的数据接口。

  • 数据抽象:视图隐藏了底层表结构和连接的复杂性,以简单、逻辑的格式呈现数据。
  • 安全性:您可以授予用户访问视图的权限,而无需授予他们访问底层表的权限,从而有效地将他们限制在特定的列或行。
  • 简洁性:视图可以封装一个复杂的、多表 JOIN 查询,允许用户像查询单个表一样查询它。

视图是使用 CREATE VIEW 语句创建的。OR REPLACE 子句通常用于更新现有视图定义,而无需先删除它。

CREATE [ OR REPLACE ] [ TEMP | TEMPORARY ] VIEW view_name AS
SELECT column1, column2, ...
FROM table_name
WHERE [condition];

TEMP 或 TEMPORARY 关键字创建一个视图,该视图在当前会话结束时自动删除。

假设我们有一个 employees 表:

CREATE TABLE employees (
id SERIAL PRIMARY KEY,
first_name VARCHAR(50),
last_name VARCHAR(50),
email VARCHAR(100) UNIQUE,
salary NUMERIC(10, 2),
department_id INT
);
INSERT INTO employees (first_name, last_name, email, salary, department_id)
VALUES
('Alice', 'Williams', 'alice.w@example.com', 75000.00, 1),
('Bob', 'Johnson', 'bob.j@example.com', 82000.00, 1),
('Charlie', 'Brown', 'charlie.b@example.com', 68000.00, 2);

现在,我们来创建一个视图,它只显示员工姓名和电子邮件,隐藏敏感的薪资信息。

CREATE OR REPLACE VIEW employee_directory AS
SELECT first_name, last_name, email
FROM employees
ORDER BY last_name, first_name;

您现在可以像查询表一样查询此视图:

SELECT * FROM employee_directory;

这将产生以下结果:

first_name | last_name | email
------------+-----------+-----------------------
Charlie | Brown | charlie.b@example.com
Bob | Johnson | bob.j@example.com
Alice | Williams | alice.w@example.com
(3 rows)

如果视图满足某些条件,它将自动可更新(即,您可以在其上运行 INSERT、UPDATE 或 DELETE 操作),主要条件是它基于单个表,并且不使用聚合、DISTINCT、GROUP BY 等。对于复杂的、不可更新的视图,您可以定义 INSTEAD OF 触发器来指定尝试修改时应发生什么。

注意:过去有时会为此目的使用 RULE,但 INSTEAD OF 触发器是现代且更灵活的最佳实践。

对于性能关键型查询,PostgreSQL 提供了物化视图(MATERIALIZED VIEW)。与标准视图不同,物化视图物理存储其结果集。这提供了更快的读取访问速度,但需要您手动 REFRESH(刷新)视图才能看到底层表的更改。

CREATE MATERIALIZED VIEW high_earners AS
SELECT id, first_name, last_name FROM employees WHERE salary > 80000;
-- 要更新物化视图中的数据:
REFRESH MATERIALIZED VIEW high_earners;

要删除视图,请使用 DROP VIEW 语句。使用 CASCADE 可以自动删除依赖于该视图的任何对象。

DROP VIEW view_name; -- 如果其他对象依赖于它,则失败(默认是 RESTRICT)
DROP VIEW view_name CASCADE; -- 删除视图及依赖对象

要删除我们创建的 employee_directory 视图:

DROP VIEW employee_directory;