🎯 本月只剩几天支持 SQLTest.online,帮助我们让 SQL 练习对每个人都免费。 今天捐赠 →
SQL 代码已复制到剪贴板

SQL 中的视图(VIEW)

第 9.5 课 · 阅读时间:约 8 分钟 · 练习题 ↓

本课介绍视图(VIEW)。视图是一种 SQL 对象,可以把一条查询以某个名称保存下来,之后像使用普通表一样使用它。你将学习如何创建视图、视图与表和临时表有何不同,以及它在哪些任务中特别有用。学完本课后,你将能够熟练地用视图简化复杂查询并复用逻辑。

在上一课中,我们讨论了临时表,它可以在会话期间保存中间结果。现在来看 SQL 中另一个重要工具:视图。视图同样能简化复杂查询的处理,但方式不同。

视图允许你把一条 SELECT 查询以单独的名称保存下来,之后反复使用。这在报表、分析以及需要多次读取同一结果集的场景中特别有用。

SQL 视图

什么是视图

视图(VIEW)是一种数据库对象,它保存的不是数据本身,而是用于获取数据的 SQL 查询。

简单来说,可以把视图看作一张“虚拟表”:

  • 它有名称;
  • 可以用 SELECT 查询;
  • 通常显示来自一张或多张表的数据;
  • 有助于把复杂的查询逻辑隐藏在更简单的接口后面。

当你查询视图时,DBMS 通常会执行保存的查询,并根据底层表返回当前的结果。

基本语法

视图用 CREATE VIEW 创建:

CREATE VIEW view_name AS
SELECT column1, column2, column3
FROM table_name
WHERE condition;

之后几乎可以像查询表一样查询视图:

SELECT *
FROM view_name;

需要明白的是,普通视图保存的是查询逻辑,而不是结果的独立副本。

如果不再需要某个视图,可以用 DROP VIEW 删除:

DROP VIEW view_name;

在许多 DBMS 中,更安全的写法是 DROP VIEW IF EXISTS view_name;,它只在对象存在时才删除,有助于避免部署脚本出错。

示例:创建视图

假设我们经常需要获取客户列表及其付款总额。与其每次都写同样的查询,不如创建一个视图:

CREATE VIEW customer_payment_summary AS
SELECT c.customer_id,
       c.first_name,
       c.last_name,
       SUM(p.amount) AS total_amount,
       COUNT(p.payment_id) AS payment_count
FROM customer c
JOIN payment p ON c.customer_id = p.customer_id
GROUP BY c.customer_id, c.first_name, c.last_name;

现在使用这段逻辑就容易多了:

SELECT customer_id, first_name, last_name, total_amount
FROM customer_payment_summary
ORDER BY total_amount DESC;

SELECT AVG(total_amount) AS avg_customer_revenue
FROM customer_payment_summary;

结果:复杂的聚合只在视图中定义一次,之后就可以在多条独立的查询中像使用普通数据集一样使用它。


视图与普通表有何不同

虽然视图看起来常常像一张表,但两者之间存在重要区别。

1. 数据存储

  • 普通表以物理方式存储数据。
  • 视图通常只保存 SQL 查询。

2. 结果来源

  • 普通表包含自己的行。
  • 视图显示从其他表甚至其他视图中获取的数据。

3. 数据的时效性

  • 普通表只有在 INSERT、UPDATE 或 DELETE 之后才会变化。
  • 视图通常显示查询时底层表的当前状态。

4. 用途

  • 普通表用于存储业务数据。
  • 视图用于简化读取、复用查询以及对查询进行逻辑组织。

5. 数据修改

  • 普通表本身就是用来插入、更新和删除行的。
  • 视图在某些情况下也支持修改数据,但这取决于具体的 DBMS,以及 VIEW 内部查询的复杂程度。

视图在什么情况下特别有用

在以下情况下值得使用视图:

  • 同一条查询需要重复很多次;
  • 想把复杂的 JOIN、过滤和聚合隐藏在一个更简单的名称后面;
  • 想让用户或报表只能访问需要的列和行,而不是整张表;
  • 想让分析型 SQL 更易读、更易维护。

例如,可以只为高价电影创建一个视图:

CREATE VIEW expensive_films AS
SELECT film_id, title, rental_rate, rating
FROM film
WHERE rental_rate >= 4.00;

SELECT title, rental_rate
FROM expensive_films
ORDER BY rental_rate DESC, title;

结果:主要的过滤逻辑保存在一个地方,因此在后续查询中不必每次都重复写 WHERE rental_rate >= 4.00 条件。


视图与临时表

视图和临时表可以解决类似的任务,但两者之间存在重要区别。

  • 临时表通常只在有限的时间内存在,并单独存储中间数据。
  • 视图通常是模式中的永久对象,只保存查询。
  • 当需要在多个步骤中以物理方式保留中间结果时,临时表更方便。
  • 当需要多次复用同一选取逻辑时,视图更方便。
  • 临时表更多用于数据处理流程内部。
  • 视图更多用作访问数据的便捷命名层。

如果需要一个单独存在、可能还要继续处理的中间结果,临时表通常是更好的选择。如果只需要在现有数据之上一次性定义一个方便的表示,VIEW 通常更合适。


能否通过视图修改数据

在许多 DBMS 中,简单的视图不仅可以用于读取,还可以用于修改数据。例如,如果视图基于单张表,并且不包含复杂的聚合、GROUP BY、DISTINCT 或多表连接,就可能做到这一点。

例如,一个简单的视图可以是这样的:

CREATE VIEW active_customers_basic AS
SELECT customer_id, first_name, last_name, active
FROM customer
WHERE active = 1;

在某些 DBMS 中,可以通过这样的视图执行 UPDATE。但不要把它当作通用规则:视图的逻辑越复杂,它可更新的可能性就越小。

在实践中,视图更多用于读取和简化查询。


需要注意的地方

使用视图时,最好记住以下几条规则:

  • 给视图起清晰、能反映其含义的名称;
  • 如果会让视图难以阅读,就不要在一个视图中隐藏过多逻辑;
  • 记住,查询视图的性能取决于视图内部的查询和底层表;
  • 不要想当然地认为任何视图都支持 INSERT、UPDATE 或 DELETE;
  • 在具体任务中,检查使用普通 SELECT、CTE 或临时表是否会更简单;
  • 考虑 DBMS 的特有功能,例如 CREATE OR REPLACE VIEW 或视图可更新性的规则。

设计良好的视图能让 SQL 更简短、更清晰、更易复用。


实践示例

假设分析人员经常需要电影列表及其类别名称。与其每次都写同样的 JOIN,不如创建一个视图:

CREATE VIEW film_category_details AS
SELECT f.film_id,
       f.title,
       f.rental_rate,
       c.name AS category_name
FROM film f
JOIN film_category fc ON f.film_id = fc.film_id
JOIN category c ON fc.category_id = c.category_id;

之后,任何查询都会变得更简单:

SELECT title, category_name, rental_rate
FROM film_category_details
WHERE category_name = 'Comedy'
ORDER BY rental_rate DESC, title;

SELECT category_name, COUNT(*) AS film_count
FROM film_category_details
GROUP BY category_name
ORDER BY film_count DESC;

这种做法很方便,因为复杂的表关系只需定义一次。之后,分析人员、报表和应用都可以使用这个现成的逻辑层,而不必反复编写同样的 JOIN 逻辑。


常见问题

视图存储的是数据还是只是查询?

在标准实现中,VIEW 只保存 SQL 定义,而不是行的独立副本。查询视图时,DBMS 会根据底层表构建结果。

什么时候应该选择视图而不是临时表?

当需要多次复用同一读取逻辑时,VIEW 更好。当需要在多个处理步骤中以物理方式保留中间结果时,临时表更好。

视图本身能提升性能吗?

不会自动提升。性能取决于 VIEW 内部的查询、源表上的索引以及执行计划。


面试问题

什么是 SQL 视图,它如何工作?

视图是保存为模式对象的命名 SQL 查询。当你对它执行 SELECT 时,DBMS 会执行保存的定义,并以虚拟表的形式返回结果。

视图与普通表有何不同?

普通表以物理方式存储数据。视图通常只保存查询逻辑,用于简化访问和复用复杂的查询模式。

视图在什么情况下可以更新?

通常是基于单张表、不包含 GROUP BY、聚合、DISTINCT 或复杂连接的简单视图。具体规则取决于 DBMS。


本课要点:

  • 视图(VIEW)保存的是 SQL 查询,而不是数据的独立副本。
  • 可以像查询表一样查询视图,这简化了复杂逻辑的复用。
  • 视图在报表、分析以及隐藏复杂的 JOIN 和过滤条件方面特别有用。
  • 与临时表不同,视图通常是模式中的永久对象,并不用于存储中间数据。
  • 并非所有视图都支持修改数据,这取决于具体的 DBMS 和查询结构。
  • 视图的性能取决于其内部查询编写得是否高效。

尝试解决以下任务,以巩固您在本课中学到的内容。

  1. 企鹅分布视图
  2. 从数据库中删除视图
  3. RDBMS中的视图是什么?
  4. 创建客户地址视图
  5. 企鹅平均值视图