CREATE VIEW
CREATE VIEW — 定义一个新视图
大纲
CREATE [ OR REPLACE ] [ TEMP | TEMPORARY ] [ RECURSIVE ] VIEWname[ (column_name[, ...] ) ] [ WITH (view_option_name[=view_option_value] [, ... ] ) ] ASquery[ WITH [ CASCADED | LOCAL ] CHECK OPTION ]
描述
CREATE VIEW 定义一个视图,其内容来自一个查询。该视图不会被实际物化。相反,每次在查询中引用该视图时,都会执行定义它的查询。
CREATE OR REPLACE VIEW 与之类似,但如果已经存在同名视图,则会用新定义替换它。新查询必须生成与现有视图查询相同的列(即列名、列顺序和数据类型都相同),但可以在列表末尾附加额外的列。生成输出列的计算方式则可以完全不同。
如果给出了模式名称(例如,CREATE VIEW
myschema.myview ...),则视图将在指定的模式中创建。否则,它将在当前模式中创建。临时视图存在于一个特殊模式中,因此在创建临时视图时不能给出模式名称。视图的名称必须与同一模式中的任何其他关系(表、序列、索引、视图、物化视图或外部表)的名称不同。
参数
TEMPORARY或TEMP#如果指定该选项,视图将被创建为临时视图。临时视图会在当前会话结束时自动删除。当临时视图存在时,除非使用模式限定名称引用,否则具有相同名称的现有永久关系对当前会话不可见。
如果视图引用的任何表是临时表,则该视图也会被创建为临时视图(无论是否指定了
TEMPORARY)。RECURSIVE#创建一个递归视图。语法
CREATE RECURSIVE VIEW [
schema. ]view_name(column_names) AS SELECT...;等效于
CREATE VIEW [
schema. ]view_nameAS WITH RECURSIVEview_name(column_names) AS (SELECT...) SELECTcolumn_namesFROMview_name;递归视图必须指定视图列名列表。
name#要创建的视图名称(可以带模式限定)。
column_name#视图各列使用的名称列表,可选。若未给出,则从查询中推断列名。
WITH (#view_option_name[=view_option_value] [, ... ] )该子句为视图指定可选参数;支持以下参数:
以上所有选项都可以通过
ALTER VIEW在现有视图上修改。query#WITH [ CASCADED | LOCAL ] CHECK OPTION#该选项控制自动可更新视图的行为。指定该选项时,会检查对该视图执行的
INSERT和UPDATE命令,以确保新行满足视图定义条件(即确保能够通过该视图看到这些新行)。如果不满足条件,该修改将被拒绝。若未指定CHECK OPTION,则允许在该视图上执行INSERT和UPDATE命令来创建通过该视图不可见的行。支持以下检查选项:CHECK OPTION不能与RECURSIVE视图一起使用。注意,
CHECK OPTION仅支持自动可更新且不带INSTEAD OF触发器或INSTEAD规则的视图。如果一个自动可更新视图定义在带有INSTEAD OF触发器的基视图之上,则可以使用LOCAL CHECK OPTION检查该自动可更新视图的条件,但不会检查带有INSTEAD OF触发器的基视图上的条件(级联检查选项不会继续向下级联到触发器可更新视图,而直接定义在触发器可更新视图上的任何检查选项也会被忽略)。如果该视图或其任何基关系带有会导致INSERT或UPDATE命令被重写的INSTEAD规则,则在重写后的查询中所有检查选项都会被忽略,包括来自定义在带有INSTEAD规则的关系之上的自动可更新视图的任何检查选项。
注解
使用 DROP VIEW 语句删除视图。
应留意视图列的名称和类型是否按预期确定。例如:
CREATE VIEW vista AS SELECT 'Hello World';
这种写法不好,因为列名默认是?column?;而且列数据类型默认是 text,这可能并非所需。若要在视图结果中使用字符串字面量,更好的写法类似于:
CREATE VIEW vista AS SELECT text 'Hello World' AS hello;
默认情况下,访问视图中引用的底层基关系时,会依据视图所有者的权限进行判断。在某些情况下,这可用于为底层表提供安全但受限的访问。然而,并非所有视图都能防止被篡改;详见第 41.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 语句。满足下列所有条件的视图是自动可更新的:
该视图的
FROM列表中必须恰好只有一项,而且这一项必须是一个表或另一个可更新视图。视图定义的顶层不能包含
WITH、DISTINCT、GROUP BY、HAVING、LIMIT或者OFFSET子句。视图定义的顶层不能包含集合操作(
UNION、INTERSECT或者EXCEPT)。视图的
SELECT列表不能包含任何聚合函数、窗口函数或集合返回函数。
自动可更新视图可以同时包含可更新列和不可更新列。如果某列只是简单引用了底层基关系中的一个可更新列,则该列是可更新的;否则,该列为只读,如果 INSERT 或 UPDATE 语句试图为其赋值,就会报错。
如果视图是自动可更新的,系统会把视图上的任何 INSERT、UPDATE 或 DELETE 语句转换为底层基关系上的对应语句。带有 ON CONFLICT UPDATE 子句的 INSERT 语句也得到完全支持。
如果自动可更新视图包含 WHERE 条件,那么在该视图上执行 UPDATE 和 DELETE 语句时,该条件会限制底层基关系中哪些行可被修改。不过,仍允许 UPDATE 把某一行改成不再满足 WHERE 条件,从而使其不再能通过该视图看到。类似地,INSERT 命令也可能插入不满足 WHERE 条件的基关系行,因此这些行通过该视图不可见(ON CONFLICT UPDATE 也可能类似地影响现有的、通过该视图不可见的行)。可以使用 CHECK OPTION 阻止 INSERT 和 UPDATE 命令创建这类通过该视图不可见的行。
如果自动可更新视图带有 security_barrier 属性,那么视图上的所有 WHERE 条件(以及任何使用标记为
LEAKPROOF 的操作符的条件)总会先于视图使用者添加的任何条件求值。详见第 41.5 节。请注意,因此那些最终不会返回的行(因为它们未通过用户的 WHERE 条件)仍可能被锁定。可以使用 EXPLAIN 查看哪些条件是在关系级别应用的(因而不会锁定行),哪些则不是。
默认情况下,不满足所有这些条件的更复杂视图是只读的:系统不允许在该视图上执行插入、更新或删除。可以通过在视图上创建 INSTEAD OF 触发器来实现可更新视图的效果;这些触发器必须把针对该视图的插入等操作转换为在其他表上执行的适当动作。有关更多信息,请参见 CREATE TRIGGER。另一种可能性是创建规则(参见 CREATE RULE),但实际上触发器更容易理解和正确使用。
注意,在视图上执行插入、更新或删除的用户,必须拥有该视图上相应的插入、更新或删除权限。另外,默认情况下,视图所有者必须在底层基关系上拥有相关权限,而执行更新的用户则不需要在底层基关系上拥有任何权限(参见第 41.5 节)。但是,如果视图的
security_invoker 设置为 true,则必须由执行更新的用户而非视图所有者,在底层基关系上拥有相关权限。
示例
创建一个由所有喜剧影片组成的视图:
CREATE VIEW comedies AS
SELECT *
FROM films
WHERE kind = 'Comedy';
这会创建一个视图,其中包含创建视图时 films 表中的各列。尽管创建视图时使用了*,但以后添加到该表的列不会成为该视图的一部分。
创建带有 LOCAL CHECK OPTION 的视图:
CREATE VIEW universal_comedies AS
SELECT *
FROM comedies
WHERE classification = 'U'
WITH LOCAL CHECK OPTION;
这会创建一个基于视图 comedies 的视图,只显示
kind = 'Comedy' 且
classification = 'U' 的影片。如果新行不满足
classification = 'U',则任何对该视图执行
INSERT 或 UPDATE 的尝试都会被拒绝,但不会检查影片的 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 ( ... ) 子句同样是扩展,安全屏障视图和安全调用者视图也是如此。
报告文档问题
阅读 上游文档. 通过 PostgreSQL 文档反馈表单.