CREATE VIEW¶
基于对一个或多个现有表(或任何其他有效查询表达式)的查询,在当前/指定的架构中创建新视图。
语法¶
CREATE [ OR REPLACE ] [ SECURE ] [ { [ { LOCAL | GLOBAL } ] TEMP | TEMPORARY | VOLATILE } ] [ RECURSIVE ] VIEW [ IF NOT EXISTS ] <name>
[ ( <column_list> ) ]
[ <col1> [ WITH ] MASKING POLICY <policy_name> [ USING ( <col1> , <cond_col1> , ... ) ]
[ WITH ] PROJECTION POLICY <policy_name>
[ WITH ] TAG ( <tag_name> = '<tag_value>' [ , <tag_name> = '<tag_value>' , ... ] ) ]
[ , <col2> [ ... ] ]
[ [ WITH ] ROW ACCESS POLICY <policy_name> ON ( <col_name> [ , <col_name> ... ] ) ]
[ [ WITH ] TAG ( <tag_name> = '<tag_value>' [ , <tag_name> = '<tag_value>' , ... ] ) ]
[ COPY GRANTS ]
[ COMMENT = '<string_literal>' ]
[ [ WITH ] ROW ACCESS POLICY <policy_name> ON ( <col_name> [ , <col_name> ... ] ) ]
[ [ WITH ] AGGREGATION POLICY <policy_name> ]
[ [ WITH ] TAG ( <tag_name> = '<tag_value>' [ , <tag_name> = '<tag_value>' , ... ] ) ]
AS <select_statement>
必填参数¶
name
指定视图的标识符;对于在其中创建视图的架构来说,此标识符必须是唯一的。
此外,标识符必须以字母字符开头,且不能包含空格或特殊字符,除非整个标识符字符串放在双引号内(例如,
"My object"
)。放在双引号内的标识符也区分大小写。有关更多详细信息,请参阅 标识符要求。
select_statement
指定用于创建视图的查询。可以位于一个或多个源表或任何其他有效 SELECT 语句上。此查询用作视图的文本/定义,并显示在 SHOW VIEWS 输出和 VIEWS Information Schema 视图中。
可选参数¶
SECURE
指定视图为安全视图。有关安全视图的详细信息,请参阅 使用安全视图。
默认:无值(视图不是安全视图)
{ [ { LOCAL | GLOBAL } ] TEMP | TEMPORARY | VOLATILE }
指定该视图仅在创建该视图的 会话 期间持续存在。临时视图及其所有内容将在会话结束时删除。
提供
TEMPORARY
(例如GLOBAL TEMPORARY
)的同义词和缩写是为了与其他数据库兼容(例如,防止在迁移 CREATE VIEW 语句时出错)。使用这些关键字中的任何一个创建的视图的外观和行为与使用TEMPORARY
关键字创建的视图相同。默认:无值。如果视图未声明为
TEMPORARY
,则该视图是永久视图。如果希望避免意外冲突,请避免以架构中已经存在的视图命名临时视图。
如果创建了一个与架构中另一个视图同名的临时视图,那么对该视图执行的所有查询和操作只影响会话中的临时视图,直到删除临时视图为止。如果删除视图,则删除临时视图,而不是架构中已存在的视图。
RECURSIVE
指定视图可以使用递归语法引用自身,而不必使用 CTE(公共表表达式)。有关递归视图的更多信息,特别是 RECURSIVE 关键字,请参阅 递归视图(仅限非物化视图) (仅限非物化视图)和下面的递归视图示例。
默认:无值(视图不是递归的,或者仅通过使用 CTE 递归)
column_list
如果您希望在新视图中更改列的名称或向列添加注释,请包含一个列列表,该列表指定列名和(如果需要)关于列的注释。(无需指定列的数据类型。)
如果视图中的任何列都基于表达式(而不仅仅是简单的列名),则必须为视图中的每个列提供列名。例如,在以下情况下,列名是必需的:
CREATE VIEW v1 (pre_tax_profit, taxes, after_tax_profit) AS SELECT revenue - cost, (revenue - cost) * tax_rate, (revenue - cost) * (1.0 - tax_rate) FROM table1;
您可以为每列指定可选注释。例如:
CREATE VIEW v1 (pre_tax_profit COMMENT 'revenue minus cost', taxes COMMENT 'assumes taxes are a fixed percentage of profit', after_tax_profit) AS SELECT revenue - cost, (revenue - cost) * tax_rate, (revenue - cost) * (1.0 - tax_rate) FROM table1;
当列名不明确时,注释特别有用。
要查看注释,请使用 DESCRIBE VIEW。
MASKING POLICY = policy_name
指定要在列上设置的 掩码策略。
USING ( col_name , cond_col_1 ... )
指定要传递到条件掩码策略 SQL 表达式的实参。
列表中的第一列指定用于掩码处理或标记数据的策略条件的列,并且 必须 与设置掩码策略的列匹配。
附加列指定要评估的列,以确定在对第一列进行查询时是否对查询结果的每行中的数据进行掩码处理或标记化。
如果省略 USING 子句,Snowflake 会将条件掩码策略视为正常的 掩码策略。
PROJECTION POLICY policy_name
指定要在列上设置的 投影策略。
COPY GRANTS
使用
OR REPLACE
子句创建新视图时保留原始视图的访问权限。该参数将现有视图中的所有权限( OWNERSHIP 除外)复制到新视图中。新视图 不会 继承为架构中的对象类型定义的任何未来授权。默认情况下,执行 CREATE VIEW 语句的角色拥有新视图。
如果该参数未包含在 CREATE VIEW 语句中,则新视图 不会 继承对原始视图授予的任何显式访问权限,但会继承为架构中的对象类型定义的任何未来授权。
请注意,复制授权的操作在 CREATE VIEW 语句中(即在同一事务中)自动发生。
默认:无值(不复制授权)
COMMENT = 'string_literal'
指定视图的注释。
默认:无值
ROW ACCESS POLICY policy_name ON ( col_name [ , col_name ... ] )
指定要在视图上设置的 行访问策略。
AGGREGATION POLICY policy_name
指定要在视图上设置的 聚合策略。
访问控制要求¶
权限 |
对象 |
备注 |
---|---|---|
CREATE VIEW |
架构 |
|
SELECT |
表、外部表、视图 |
在视图定义中查询的任何表和/或视图上都是必需的。 |
APPLY |
掩码策略、行访问策略、标签 |
仅在创建视图时应用掩码策略、行访问策略、对象标签或这些 治理 功能的任何组合时才需要。 |
OWNERSHIP |
视图 |
若要创建创建与架构中已存在的对象同名的临时对象,必须授予角色或使其继承对象上的 OWNERSHIP 权限。 Note that in a managed access schema, only the schema owner (i.e. the role with the OWNERSHIP privilege on the schema) or a role with the MANAGE GRANTS privilege can grant or revoke privileges on objects in the schema, including future grants. |
请注意,对架构中的对象进行操作还需要对父数据库和架构具有 USAGE 权限。
有关创建具有指定权限集的自定义角色的说明,请参阅 创建自定义角色。
使用说明¶
视图定义可以包含 ORDER BY 子句(例如
create view v1 as select * from t1 ORDER BY column1
)。但是,Snowflake 建议从大多数视图定义中 排除ORDER BY
子句。若视图在不需要排序的情况下被使用,那么添加ORDER BY
子句就会带来不必要的计算开销。例如,当视图用于联接,而联接列与ORDER BY
列不同时,通常对视图结果进行排序的额外成本都会浪费掉。如果需要对查询结果进行排序,通常在使用视图的查询中指定,而不是在视图本身中指定ORDER BY
。如果在视图定义中指定 CURRENT_DATABASE 或 CURRENT_SCHEMA 函数,该函数会返回包含视图的数据库或架构,而不是用于会话的数据库或架构。
视图的定义限制为 95KB。
嵌套级别最多限制为 20 个。尝试创建嵌套超过 20 次的视图将会失败。
视图定义不是动态的。如果修改了基础源,使其不再与视图定义匹配,则视图不会自动更新,尤其是在删除列时。例如:
在源表中创建一个引用特定列的视图,然后从表中删除该列。
使用
SELECT *
从表创建视图,并对表中的列进行更改,例如:删除一列。
添加一列。
更改列顺序。
在这些情况下,查询视图将返回与列相关的错误。
如果删除了视图的源表,则查询该视图将返回
object does not exist
错误。架构不能包含同名的表和视图。如果架构中已存在同名的表,则 CREATE VIEW 语句将产生错误。
当创建视图时,对表和其他数据库对象的 :doc:` 非限定 </sql-reference/name-resolution>` 引用 :emph:` 在视图的架构中 ` 解析,而不是在会话的当前架构中解析。同样,部分限定的对象(即 schema.object)在视图的数据库中解析,而不是在会话的当前数据库中解析。
将忽略
SEARCH_PATH
会话参数(如果存在)。使用
OR REPLACE
相当于对现有视图执行 DROP VIEW,然后创建具有相同名称的新视图。CREATE OR REPLACE <object> 语句是原子的。也就是说,当对象被替换时,旧对象将被删除,新对象将在单个事务中创建。
这意味着使用 CREATE OR REPLACE VIEW 操作执行任何并行查询都使用旧的或新的视图版本。
重新创建或交换视图会丢弃其更改数据,从而使视图上的任何流都过时。过时 的流是不可读的。
使用
COPY GRANTS
:数据共享:
如果现有安全视图已共享到另一个账户,则替换视图也会共享。
如果现有安全视图已作为数据使用者与您的账户共享,并且进一步授予了对账户中其他角色的访问权限(在父数据库上使用 GRANT IMPORTED PRIVILEGES),则还会授予对替换视图的访问权限。
替换视图的 SHOW GRANTS 输出会将复制权限的获得者列为执行 CREATE VIEW 语句的角色,并附带执行语句时的当前时间戳。
当您创建视图,然后将该视图的权限授予角色时,即使该角色对视图访问的基础表没有权限,该角色也可以使用该视图。这意味着您可以创建一个视图,以便仅向角色授予对表子集的访问权限。例如,您可以创建一个视图,该视图访问同一表中的医疗账单信息,但不访问医疗诊断信息。然后,您可以将该视图的权限授予“会计师”角色,以便会计师可以在不查看患者诊断信息的情况下查看账单信息。
根据设计,该 SHOW VIEWS 命令不提供有关安全视图的信息。若要查看有关安全视图的信息,必须使用 Information Schema 中的 VIEWS 视图,并且必须使用拥有该视图的角色。
递归视图必须提供列名列表。
定义递归视图时,请防止无限递归。递归视图定义中的 WHERE 子句应使递归最终停止,通常是在处理完数据层次结构的最后一层后耗尽数据。
关于元数据:
注意
客户应确保在使用 Snowflake 服务时,不会将个人数据(用户对象除外)、敏感数据、出口管制数据或其他受监管数据作为元数据输入。有关更多信息,请参阅 Snowflake 中的元数据字段。
在一个或多个视图列上使用掩码策略创建视图或将行访问策略添加到视图时,请使用 POLICY_CONTEXT 函数模拟对受掩码策略保护的列和受行访问策略保护的视图的查询。
请勿创建将流作为源对象的视图,除非同一个角色同时拥有视图和源流(即,同一个角色,或者角色层次结构中较低的角色,对视图和源流拥有 OWNERSHIP 权限)。相反,创建具有要跟踪的对象作为源对象的视图。然后,在这些视图上创建流。有关更多信息,请参阅 视图上的流。
移植说明¶
一些供应商支持
FORCE
关键字:CREATE OR REPLACE FORCE VIEW ...
Snowflake 接受
FORCE
关键字,但不支持它。换言之,如果使用此关键字,则不会出现语法错误,但如果基础数据库对象(表或视图)尚不存在,则使用FORCE
不会强制创建视图。即使使用了FORCE
关键字,尝试创建不存在的表或视图的视图也会导致错误消息。在视图中查找表时,某些供应商会在活动架构中搜索非限定表名称;Snowflake 在 :ref:` 与视图相同的模式 <label-views_introduction__unqualified_table_schema_equals_view_schema>` 中搜索未限定表名。移植到 Snowflake 时,请考虑更新视图以使用完全限定的表名。
示例¶
在当前架构中创建一个带有注释的视图,该视图从表中选择所有行:
CREATE VIEW myview COMMENT='Test view' AS SELECT col1, col2 FROM mytable; SHOW VIEWS; +---------------------------------+-------------------+----------+---------------+-------------+----------+-----------+--------------------------------------------------------------------------+ | created_on | name | reserved | database_name | schema_name | owner | comment | text | |---------------------------------+-------------------+----------+---------------+-------------+----------+-----------+--------------------------------------------------------------------------| | Thu, 19 Jan 2017 15:00:37 -0800 | MYVIEW | | MYTEST1 | PUBLIC | SYSADMIN | Test view | CREATE VIEW myview COMMENT='Test view' AS SELECT col1, col2 FROM mytable | +---------------------------------+-------------------+----------+---------------+-------------+----------+-----------+--------------------------------------------------------------------------+
下一个示例与上一个示例相同,只是视图是安全的:
CREATE OR REPLACE SECURE VIEW myview COMMENT='Test secure view' AS SELECT col1, col2 FROM mytable; SELECT is_secure FROM information_schema.views WHERE table_name = 'MYVIEW';
下面显示了创建递归视图的两种方法:
第一,创建并加载表:
CREATE OR REPLACE TABLE employees (title VARCHAR, employee_ID INTEGER, manager_ID INTEGER);INSERT INTO employees (title, employee_ID, manager_ID) VALUES ('President', 1, NULL), -- The President has no manager. ('Vice President Engineering', 10, 1), ('Programmer', 100, 10), ('QA Engineer', 101, 10), ('Vice President HR', 20, 1), ('Health Insurance Analyst', 200, 20);使用递归 CTE 创建视图,然后查询该视图。
CREATE VIEW employee_hierarchy (title, employee_ID, manager_ID, "MGR_EMP_ID (SHOULD BE SAME)", "MGR TITLE") AS ( WITH RECURSIVE employee_hierarchy_cte (title, employee_ID, manager_ID, "MGR_EMP_ID (SHOULD BE SAME)", "MGR TITLE") AS ( -- Start at the top of the hierarchy ... SELECT title, employee_ID, manager_ID, NULL AS "MGR_EMP_ID (SHOULD BE SAME)", 'President' AS "MGR TITLE" FROM employees WHERE title = 'President' UNION ALL -- ... and work our way down one level at a time. SELECT employees.title, employees.employee_ID, employees.manager_ID, employee_hierarchy_cte.employee_id AS "MGR_EMP_ID (SHOULD BE SAME)", employee_hierarchy_cte.title AS "MGR TITLE" FROM employees INNER JOIN employee_hierarchy_cte WHERE employee_hierarchy_cte.employee_ID = employees.manager_ID ) SELECT * FROM employee_hierarchy_cte );SELECT * FROM employee_hierarchy ORDER BY employee_ID; +----------------------------+-------------+------------+-----------------------------+----------------------------+ | TITLE | EMPLOYEE_ID | MANAGER_ID | MGR_EMP_ID (SHOULD BE SAME) | MGR TITLE | |----------------------------+-------------+------------+-----------------------------+----------------------------| | President | 1 | NULL | NULL | President | | Vice President Engineering | 10 | 1 | 1 | President | | Vice President HR | 20 | 1 | 1 | President | | Programmer | 100 | 10 | 10 | Vice President Engineering | | QA Engineer | 101 | 10 | 10 | Vice President Engineering | | Health Insurance Analyst | 200 | 20 | 20 | Vice President HR | +----------------------------+-------------+------------+-----------------------------+----------------------------+使用关键字 RECURSIVE 创建视图,然后查询该视图。
CREATE RECURSIVE VIEW employee_hierarchy_02 (title, employee_ID, manager_ID, "MGR_EMP_ID (SHOULD BE SAME)", "MGR TITLE") AS ( -- Start at the top of the hierarchy ... SELECT title, employee_ID, manager_ID, NULL AS "MGR_EMP_ID (SHOULD BE SAME)", 'President' AS "MGR TITLE" FROM employees WHERE title = 'President' UNION ALL -- ... and work our way down one level at a time. SELECT employees.title, employees.employee_ID, employees.manager_ID, employee_hierarchy_02.employee_id AS "MGR_EMP_ID (SHOULD BE SAME)", employee_hierarchy_02.title AS "MGR TITLE" FROM employees INNER JOIN employee_hierarchy_02 WHERE employee_hierarchy_02.employee_ID = employees.manager_ID );SELECT * FROM employee_hierarchy_02 ORDER BY employee_ID; +----------------------------+-------------+------------+-----------------------------+----------------------------+ | TITLE | EMPLOYEE_ID | MANAGER_ID | MGR_EMP_ID (SHOULD BE SAME) | MGR TITLE | |----------------------------+-------------+------------+-----------------------------+----------------------------| | President | 1 | NULL | NULL | President | | Vice President Engineering | 10 | 1 | 1 | President | | Vice President HR | 20 | 1 | 1 | President | | Programmer | 100 | 10 | 10 | Vice President Engineering | | QA Engineer | 101 | 10 | 10 | Vice President Engineering | | Health Insurance Analyst | 200 | 20 | 20 | Vice President HR | +----------------------------+-------------+------------+-----------------------------+----------------------------+