PostgreSQL 中文参考文档
🌐 英文原版 官方 ↗

CREATE VIEW

CREATE VIEW — 定义一个新视图

Synopsis

CREATE [ OR REPLACE ] [ TEMP | TEMPORARY ] [ RECURSIVE ] VIEW name [ ( column_name [, ...] ) ]
    [ WITH ( view_option_name [= view_option_value] [, ... ] ) ]
    AS query
    [ WITH [ CASCADED | LOCAL ] CHECK OPTION ]

描述

CREATE VIEW 定义一个基于查询的视图。视图并不会被物理地物化,而是每当在查询中引用该视图时都会运行一次这个查询。

CREATE OR REPLACE VIEW 与之类似,但如果已经存在同名视图,则会将其替换。新查询必须生成与现有视图查询相同的列(即相同的列名、相同的顺序和相同的数据类型),但可以在列表末尾追加新的列。产生输出列的计算方式则可以完全不同。

如果给定了模式名(例如 CREATE VIEW myschema.myview ...),则视图会被创建在指定的模式中。否则它会创建在当前模式中。临时视图存在于一个特殊的模式中,因此创建临时视图时不能指定模式名。视图的名字必须与同一模式中任何其他关系(表、序列、索引、视图、物化视图或外部表)的名字不同。

参数

TEMPORARY or TEMP

如果指定了此选项,视图将被创建为临时视图。临时视图会在当前会话结束时被自动删除。在临时视图存在期间,当前会话将看不到与其同名的已有永久关系,除非用带模式限定的名称来引用它们。

如果视图所引用的表中存在临时表,则该视图会被创建为临时视图(无论是否指定了 TEMPORARY)。

RECURSIVE

创建一个递归视图。语法

CREATE RECURSIVE VIEW [ schema . ] view_name (column_names) AS SELECT ...;

等价于

CREATE VIEW [ schema . ] view_name AS WITH RECURSIVE view_name (column_names) AS (SELECT ...) SELECT column_names FROM view_name;

递归视图必须指定视图列名列表。

name

要创建的视图的名字(可以用模式限定)。

column_name

一个可选的名称列表,用作视图各列的名字。如果不给出,列名将从查询中推导得到。

WITH ( view_option_name [= view_option_value] [, ... ] )

该子句为视图指定可选参数;支持以下参数:

check_option (enum)

该参数可以是 local 或 cascaded,等价于指定 WITH [ CASCADED | LOCAL ] CHECK OPTION(见下文)。

security_barrier (boolean)

如果该视图旨在提供行级安全,则应使用此选项。完整细节参见 Section 39.5。

security_invoker (boolean)

此选项使得对底层基础关系的检查基于视图使用者的特权而非视图所有者的特权。完整细节参见下文注记。

All of the above options can be changed on existing views using ALTER VIEW.

query

一条 SELECT 或 VALUES 命令,它将提供视图的列和行。

WITH [ CASCADED | LOCAL ] CHECK OPTION

该选项控制自动可更新视图的行为。指定该选项后,视图上的 INSERT、UPDATE 和 MERGE 命令会被检查,以确保新行满足视图定义条件(也就是说,会检查新行以确保它们可以通过该视图看到)。如果不满足,更新将被拒绝。如果未指定 CHECK OPTION,则允许视图上的 INSERT、UPDATE 和 MERGE 命令创建无法通过该视图看到的行。支持以下检查选项:

LOCAL

新行只会根据直接在该视图自身中定义的条件进行检查。在底层基础视图上定义的条件不会被检查(除非它们也指定了 CHECK OPTION)。

CASCADED

新行会依据该视图以及所有底层基础视图的条件进行检查。如果指定了 CHECK OPTION,但既未指定 LOCAL 也未指定 CASCADED,则默认假定 CASCADED。

CHECK OPTION 不能用于 RECURSIVE 视图。

请注意,CHECK OPTION 只支持自动可更新且没有 INSTEAD OF 触发器或 INSTEAD 规则的视图。如果一个自动可更新视图定义在带有 INSTEAD OF 触发器的基础视图之上,则可以使用 LOCAL CHECK OPTION 来检查该自动可更新视图上的条件,但带 INSTEAD OF 触发器的基础视图上的条件将不会被检查(级联检查选项不会级联到由触发器实现更新的视图,而且直接定义在由触发器实现更新的视图上的任何检查选项都会被忽略)。如果该视图或其任何基础关系拥有一个 INSTEAD 规则,导致 INSERT 或 UPDATE 命令被重写,那么重写后的查询将忽略所有检查选项,包括定义在带 INSTEAD 规则的关系之上的自动可更新视图所要求的检查。如果该视图或其任何基础关系拥有规则,则不支持 MERGE。

注记

使用 DROP VIEW 语句来删除视图。

请小心确保视图列的名称和类型按照你想要的方式被赋值。例如:

CREATE VIEW vista AS SELECT 'Hello World';

是一种糟糕的形式,因为列名会默认为 ?column?;此外,列的数据类型会默认为 text,这可能不是你想要的。在视图结果中书写字符串字面量的更好风格类似于:

CREATE VIEW vista AS SELECT text 'Hello World' AS hello;

默认情况下,对视图所引用的底层基础关系的访问由视图所有者的权限决定。在某些情况下,这可用于提供对底层表安全但受限的访问。然而,并非所有视图都能防范篡改;详情参见 Section 39.5。

如果视图的 security_invoker 属性被设置为 true,则对底层基础关系的访问由执行查询的用户的权限决定,而不是视图所有者的权限。因此,安全调用者视图的使用者必须对该视图及其底层基础关系拥有相关权限。

如果任何一个底层基础关系是安全调用者视图,它将被视作直接从原始查询访问一样。因此,安全调用者视图总是会使用当前用户的权限来检查其底层基础关系,即使它是从一个没有 security_invoker 属性的视图中被访问的。

如果任何一个底层基础关系启用了 行级安全,那么默认情况下会应用视图所有者的行级安全策略,并且这些策略所引用的任何附加关系的访问由视图所有者的权限决定。但是,如果视图的 security_invoker 设置为 true,则改用调用者的策略和权限,就好像这些基础关系是直接从使用该视图的查询中引用的一样。

在视图中调用的函数被视为与直接从使用该视图的查询中调用一样。因此,视图的使用者必须具有调用视图所用到的所有函数的权限。视图中的函数以执行查询的用户的特权或函数所有者的特权执行,取决于函数被定义为 SECURITY INVOKER 还是 SECURITY DEFINER。例如,在视图中直接调用 CURRENT_USER 将总是返回调用者用户,而不是视图所有者。这一点不受视图的 security_invoker 设置影响,因此 security_invoker 设置为 false 的视图不等价于 SECURITY DEFINER 函数,不应混淆这两个概念。

创建或替换视图的用户必须对视图查询中引用的任何模式拥有 USAGE 特权,以便在这些模式中查找被引用的对象。但请注意,这种查找只在视图被创建或替换时发生。因此,视图的使用者只需要对包含该视图的模式拥有 USAGE 特权,而不需要对视图查询中引用的模式拥有该特权,即使是安全调用者视图也是如此。

在现有视图上使用 CREATE OR REPLACE VIEW 时,只有视图的定义性 SELECT 规则、任何 WITH ( ... ) 参数以及它的 CHECK OPTION 会被更改。视图的其他属性(包括所有权、权限和非 SELECT 规则)保持不变。你必须拥有该视图才能替换它(这包括作为拥有该视图的角色的成员)。

可更新视图

简单视图是自动可更新的:系统允许在视图上像在普通表上一样使用 INSERT、UPDATE、DELETE 和 MERGE 语句。如果视图满足以下所有条件,则它是自动可更新的:

  • 视图的 FROM 列表中必须恰好有一个条目,并且该条目必须是一个表或另一个可更新视图。

  • 视图定义的顶层不得包含 WITH、DISTINCT、GROUP BY、HAVING、LIMIT 或 OFFSET 子句。

  • 视图定义的顶层不得包含集合操作(UNION、INTERSECT 或 EXCEPT)。

  • 视图的选择列表不得包含任何聚集函数、窗口函数或集合返回函数。

自动可更新视图可以同时包含可更新列和不可更新列。如果某列只是对底层基础关系的一个可更新列的简单引用,则该列是可更新的;否则该列是只读的,如果 INSERT、UPDATE 或 MERGE 语句试图为它赋值,将会引发错误。

如果视图是自动可更新的,系统会把视图上的任何 INSERT、UPDATE、DELETE 或 MERGE 语句转换成对底层基础关系的相应语句。INSERT 语句带有 ON CONFLICT UPDATE 子句时被完全支持。

如果自动可更新视图包含 WHERE 条件,该条件会限制基础关系的哪些行可以被视图上的 UPDATE、DELETE 和 MERGE 语句修改。不过,UPDATE 或 MERGE 允许修改某一行使其不再满足 WHERE 条件,从而不再能通过该视图看到。类似地,INSERT 或 MERGE 命令可能插入不满足 WHERE 条件因而无法通过视图看到的基础关系行(ON CONFLICT UPDATE 也可能以类似方式影响一个无法通过视图看到的现有行)。可以使用 CHECK OPTION 来阻止 INSERT、UPDATE 和 MERGE 命令创建这种无法通过视图看到的行。

如果自动可更新视图被标记了 security_barrier 属性,那么该视图的所有 WHERE 条件(以及任何使用被标记为 LEAKPROOF 的操作符的条件)将总是在视图使用者添加的任何条件之前被求值。完整细节参见 Section 39.5。请注意,正因如此,最终未被返回的行(因为它们未通过使用者的 WHERE 条件)仍可能最终被锁定。可以使用 EXPLAIN 来查看哪些条件在关系层级上被应用(因而不会锁定行),哪些条件没有。

一个不满足所有这些条件的更复杂的视图默认是只读的:系统将不允许在该视图上执行 INSERT、UPDATE、DELETE 或 MERGE。你可以通过在该视图上创建 INSTEAD OF 触发器来获得可更新视图的效果,这些触发器必须把在视图上尝试的插入等操作转换为对其他表的适当动作。更多信息参见 CREATE TRIGGER。另一种做法是创建规则(参见 CREATE RULE),但在实践中触发器更容易被正确理解和使用。还要注意,MERGE 在带有规则的关系上不受支持。

请注意,在视图上执行插入、更新或删除的用户必须对该视图拥有相应的插入、更新或删除特权。此外,默认情况下,视图所有者必须对底层基础关系拥有相关特权,而执行更新的用户则不需要对底层基础关系有任何权限(参见 Section 39.5)。但是,如果视图的 security_invoker 设置为 true,则必须是执行更新的用户(而不是视图所有者)对底层基础关系拥有相关特权。

示例

创建一个由所有喜剧电影组成的视图:

CREATE VIEW comedies AS
    SELECT *
    FROM films
    WHERE kind = 'Comedy';

这将创建一个视图,其中包含创建视图那一刻 film 表中的列。虽然创建视图时使用了 *,但之后加到表中的列不会成为视图的一部分。

创建一个带 LOCAL CHECK OPTION 的视图:

CREATE VIEW universal_comedies AS
    SELECT *
    FROM comedies
    WHERE classification = 'U'
    WITH LOCAL CHECK OPTION;

这将基于 comedies 视图创建一个视图,只显示 kind = 'Comedy' 且 classification = 'U' 的电影。任何在视图中 INSERT 或 UPDATE 行的尝试,如果新行不满足 classification = 'U' 都将被拒绝,但电影的 kind 不会被检查。

创建一个带 CASCADED CHECK OPTION 的视图:

CREATE VIEW pg_comedies AS
    SELECT *
    FROM comedies
    WHERE classification = 'PG'
    WITH CASCADED CHECK OPTION;

这将创建一个对新行的 kind 和 classification 都进行检查的视图。

创建一个同时包含可更新列和不可更新列的视图:

CREATE VIEW comedies AS
    SELECT f.*,
           country_code_to_name(f.country_code) AS country,
           (SELECT avg(r.rating)
            FROM user_ratings r
            WHERE r.film_id = f.id) AS avg_rating
    FROM films f
    WHERE f.kind = 'Comedy';

该视图将支持 INSERT、UPDATE 和 DELETE。来自 films 表的所有列都是可更新的,而计算列 country 和 avg_rating 将是只读的。

创建一个由 1 到 100 的数字组成的递归视图:

CREATE RECURSIVE VIEW public.nums_1_100 (n) AS
    VALUES (1)
UNION ALL
    SELECT n+1 FROM nums_1_100 WHERE n < 100;

请注意,尽管在这个 CREATE 中递归视图的名字带了模式限定,但其内部的自引用没有带模式限定。这是因为隐式创建的 CTE 的名字不能带模式限定。

兼容性

CREATE OR REPLACE VIEW 是 PostgreSQL 的语言扩展。临时视图的概念也是如此。WITH ( ... ) 子句也是一种扩展,安全屏障视图和安全调用者视图同样如此。

另请参阅

ALTER VIEW, DROP VIEW, CREATE MATERIALIZED VIEW